diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 7bb70716a4..ae980f1c7e 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -87,7 +87,7 @@ type Verifier interface { VerifyHeader(header *types.Header) error ProcessHeaders(headers []*types.Header) error GetBlockCreator(header *types.Header) (types.Address, error) - PreStateCommit(header *types.Header, txn *state.Transition) error + PreCommitState(header *types.Header, txn *state.Transition) error } type Executor interface { @@ -843,7 +843,7 @@ func (b *Blockchain) executeBlockTransactions(block *types.Block) (*BlockResult, return nil, err } - if err := b.consensus.PreStateCommit(header, txn); err != nil { + if err := b.consensus.PreCommitState(header, txn); err != nil { return nil, err } diff --git a/blockchain/testing.go b/blockchain/testing.go index 49a1efefdd..257ef5dc5d 100644 --- a/blockchain/testing.go +++ b/blockchain/testing.go @@ -262,14 +262,14 @@ func (m *MockVerifier) GetBlockCreator(header *types.Header) (types.Address, err return m.getBlockCreatorFn(header) } - return header.Miner, nil + return types.BytesToAddress(header.Miner), nil } func (m *MockVerifier) HookGetBlockCreator(fn getBlockCreatorDelegate) { m.getBlockCreatorFn = fn } -func (m *MockVerifier) PreStateCommit(header *types.Header, txn *state.Transition) error { +func (m *MockVerifier) PreCommitState(header *types.Header, txn *state.Transition) error { if m.preStateCommitFn != nil { return m.preStateCommitFn(header, txn) } @@ -277,7 +277,7 @@ func (m *MockVerifier) PreStateCommit(header *types.Header, txn *state.Transitio return nil } -func (m *MockVerifier) HookPreStateCommit(fn preStateCommitDelegate) { +func (m *MockVerifier) HookPreCommitState(fn preStateCommitDelegate) { m.preStateCommitFn = fn } diff --git a/chain/chain.go b/chain/chain.go index 7c273c986e..d02f42080d 100644 --- a/chain/chain.go +++ b/chain/chain.go @@ -68,7 +68,7 @@ func (g *Genesis) GenesisHeader() *types.Header { GasUsed: g.GasUsed, Difficulty: g.Difficulty, MixHash: g.Mixhash, - Miner: g.Coinbase, + Miner: g.Coinbase.Bytes(), StateRoot: stateRoot, Sha3Uncles: types.EmptyUncleHash, ReceiptsRoot: types.EmptyRootHash, diff --git a/command/common.go b/command/common.go index 323d08ebd7..4fa80d3404 100644 --- a/command/common.go +++ b/command/common.go @@ -2,8 +2,16 @@ package command import ( "errors" + "io/ioutil" + "strings" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/secrets/local" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/hashicorp/go-hclog" ) const ( @@ -11,6 +19,10 @@ const ( NoDiscoverFlag = "no-discover" BootnodeFlag = "bootnode" LogLevelFlag = "log-level" + + IBFTValidatorTypeFlag = "ibft-validator-type" + IBFTValidatorFlag = "ibft-validator" + IBFTValidatorPrefixFlag = "ibft-validators-prefix-path" ) var ( @@ -19,6 +31,10 @@ var ( errInvalidMinNumValidators = errors.New("minimum number of validators must be greater than 0") errInvalidMaxNumValidators = errors.New("maximum number of validators must be lower or equal " + "than MaxSafeJSInt (2^53 - 2)") + + ErrValidatorNumberExceedsMax = errors.New("validator number exceeds max validator number") + ErrECDSAKeyNotFound = errors.New("ECDSA key not found in given path") + ErrBLSKeyNotFound = errors.New("BLS key not found in given path") ) func ValidateMinMaxValidatorsNumber(minValidatorCount uint64, maxValidatorCount uint64) error { @@ -36,3 +52,113 @@ func ValidateMinMaxValidatorsNumber(minValidatorCount uint64, maxValidatorCount return nil } + +// GetValidatorsFromPrefixPath extracts the addresses of the validators based on the directory +// prefix. It scans the directories for validator private keys and compiles a list of addresses +func GetValidatorsFromPrefixPath( + prefix string, + validatorType validators.ValidatorType, +) (validators.Validators, error) { + files, err := ioutil.ReadDir(".") + if err != nil { + return nil, err + } + + validatorSet := validators.NewValidatorSetFromType(validatorType) + + for _, file := range files { + path := file.Name() + + if !file.IsDir() || !strings.HasPrefix(path, prefix) { + continue + } + + localSecretsManager, err := local.SecretsManagerFactory( + nil, + &secrets.SecretsManagerParams{ + Logger: hclog.NewNullLogger(), + Extra: map[string]interface{}{ + secrets.Path: path, + }, + }, + ) + if err != nil { + return nil, err + } + + address, err := getValidatorAddressFromSecretManager(localSecretsManager) + if err != nil { + return nil, err + } + + switch validatorType { + case validators.ECDSAValidatorType: + if err := validatorSet.Add(&validators.ECDSAValidator{ + Address: address, + }); err != nil { + return nil, err + } + + case validators.BLSValidatorType: + blsPublicKey, err := getBLSPublicKeyBytesFromSecretManager(localSecretsManager) + if err != nil { + return nil, err + } + + if err := validatorSet.Add(&validators.BLSValidator{ + Address: address, + BLSPublicKey: blsPublicKey, + }); err != nil { + return nil, err + } + } + } + + return validatorSet, nil +} + +func getValidatorAddressFromSecretManager(manager secrets.SecretsManager) (types.Address, error) { + if !manager.HasSecret(secrets.ValidatorKey) { + return types.ZeroAddress, ErrECDSAKeyNotFound + } + + keyBytes, err := manager.GetSecret(secrets.ValidatorKey) + if err != nil { + return types.ZeroAddress, err + } + + privKey, err := crypto.BytesToECDSAPrivateKey(keyBytes) + if err != nil { + return types.ZeroAddress, err + } + + return crypto.PubKeyToAddress(&privKey.PublicKey), nil +} + +func getBLSPublicKeyBytesFromSecretManager(manager secrets.SecretsManager) ([]byte, error) { + if !manager.HasSecret(secrets.ValidatorBLSKey) { + return nil, ErrBLSKeyNotFound + } + + keyBytes, err := manager.GetSecret(secrets.ValidatorBLSKey) + if err != nil { + return nil, err + } + + secretKey, err := crypto.BytesToBLSSecretKey(keyBytes) + if err != nil { + return nil, err + } + + pubKey, err := secretKey.GetPublicKey() + if err != nil { + return nil, err + } + + pubKeyBytes, err := pubKey.MarshalBinary() + if err != nil { + return nil, err + } + + return pubKeyBytes, nil +} diff --git a/command/genesis/genesis.go b/command/genesis/genesis.go index 3afc94d4a2..84758f41dd 100644 --- a/command/genesis/genesis.go +++ b/command/genesis/genesis.go @@ -7,6 +7,7 @@ import ( "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/consensus/ibft" "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/validators" "github.com/spf13/cobra" ) @@ -90,9 +91,16 @@ func setFlags(cmd *cobra.Command) { // IBFT Validators { + cmd.Flags().StringVar( + ¶ms.rawIBFTValidatorType, + command.IBFTValidatorTypeFlag, + string(validators.BLSValidatorType), + "the type of validators in IBFT", + ) + cmd.Flags().StringVar( ¶ms.validatorPrefixPath, - ibftValidatorPrefixFlag, + command.IBFTValidatorPrefixFlag, "", "prefix path for validator folder directory. "+ "Needs to be present if ibft-validator is omitted", @@ -100,14 +108,14 @@ func setFlags(cmd *cobra.Command) { cmd.Flags().StringArrayVar( ¶ms.ibftValidatorsRaw, - ibftValidatorFlag, + command.IBFTValidatorFlag, []string{}, "addresses to be used as IBFT validators, can be used multiple times. "+ "Needs to be present if ibft-validators-prefix-path is omitted", ) // --ibft-validator-prefix-path & --ibft-validator can't be given at same time - cmd.MarkFlagsMutuallyExclusive(ibftValidatorPrefixFlag, ibftValidatorFlag) + cmd.MarkFlagsMutuallyExclusive(command.IBFTValidatorPrefixFlag, command.IBFTValidatorFlag) } // PoS diff --git a/command/genesis/params.go b/command/genesis/params.go index 8b369e1b71..19aa3669d7 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -8,24 +8,25 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/consensus/ibft" + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/contracts/staking" stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" "github.com/0xPolygon/polygon-edge/server" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" ) const ( - dirFlag = "dir" - nameFlag = "name" - premineFlag = "premine" - chainIDFlag = "chain-id" - ibftValidatorFlag = "ibft-validator" - ibftValidatorPrefixFlag = "ibft-validators-prefix-path" - epochSizeFlag = "epoch-size" - blockGasLimitFlag = "block-gas-limit" - posFlag = "pos" - minValidatorCount = "min-validator-count" - maxValidatorCount = "max-validator-count" + dirFlag = "dir" + nameFlag = "name" + premineFlag = "premine" + chainIDFlag = "chain-id" + epochSizeFlag = "epoch-size" + blockGasLimitFlag = "block-gas-limit" + posFlag = "pos" + minValidatorCount = "min-validator-count" + maxValidatorCount = "max-validator-count" ) // Legacy flags that need to be preserved for running clients @@ -38,10 +39,9 @@ var ( ) var ( - errValidatorsNotSpecified = errors.New("validator information not specified") - errValidatorNumberExceedsMax = errors.New("validator number exceeds max validator number") - errUnsupportedConsensus = errors.New("specified consensusRaw not supported") - errInvalidEpochSize = errors.New("epoch size must be greater than 1") + errValidatorsNotSpecified = errors.New("validator information not specified") + errUnsupportedConsensus = errors.New("specified consensusRaw not supported") + errInvalidEpochSize = errors.New("epoch size must be greater than 1") ) type genesisParams struct { @@ -51,7 +51,7 @@ type genesisParams struct { validatorPrefixPath string premine []string bootnodes []string - ibftValidators []types.Address + ibftValidators validators.Validators ibftValidatorsRaw []string @@ -63,6 +63,9 @@ type genesisParams struct { minNumValidators uint64 maxNumValidators uint64 + rawIBFTValidatorType string + ibftValidatorType validators.ValidatorType + extraData []byte consensus server.ConsensusType @@ -126,6 +129,10 @@ func (p *genesisParams) getRequiredFlags() []string { func (p *genesisParams) initRawParams() error { p.consensus = server.ConsensusType(p.consensusRaw) + if err := p.initIBFTValidatorType(); err != nil { + return err + } + if err := p.initValidatorSet(); err != nil { return err } @@ -137,53 +144,77 @@ func (p *genesisParams) initRawParams() error { } // setValidatorSetFromCli sets validator set from cli command -func (p *genesisParams) setValidatorSetFromCli() { - if len(p.ibftValidatorsRaw) != 0 { - for _, val := range p.ibftValidatorsRaw { - p.ibftValidators = append( - p.ibftValidators, - types.StringToAddress(val), - ) - } +func (p *genesisParams) setValidatorSetFromCli() error { + if len(p.ibftValidatorsRaw) == 0 { + return nil + } + + newValidators, err := validators.ParseValidators(p.ibftValidatorType, p.ibftValidatorsRaw) + if err != nil { + return err + } + + if err = p.ibftValidators.Merge(newValidators); err != nil { + return err } + + return nil } // setValidatorSetFromPrefixPath sets validator set from prefix path func (p *genesisParams) setValidatorSetFromPrefixPath() error { - var readErr error - if !p.areValidatorsSetByPrefix() { return nil } - if p.ibftValidators, readErr = getValidatorsFromPrefixPath( + validators, err := command.GetValidatorsFromPrefixPath( p.validatorPrefixPath, - ); readErr != nil { - return fmt.Errorf("failed to read from prefix: %w", readErr) + p.ibftValidatorType, + ) + + if err != nil { + return fmt.Errorf("failed to read from prefix: %w", err) + } + + if err := p.ibftValidators.Merge(validators); err != nil { + return err + } + + return nil +} + +func (p *genesisParams) initIBFTValidatorType() error { + var err error + if p.ibftValidatorType, err = validators.ParseValidatorType(p.rawIBFTValidatorType); err != nil { + return err } return nil } func (p *genesisParams) initValidatorSet() error { + p.ibftValidators = validators.NewValidatorSetFromType(p.ibftValidatorType) + // Set validator set // Priority goes to cli command over prefix path if err := p.setValidatorSetFromPrefixPath(); err != nil { return err } - p.setValidatorSetFromCli() + if err := p.setValidatorSetFromCli(); err != nil { + return err + } // Validate if validator number exceeds max number if ok := p.isValidatorNumberValid(); !ok { - return errValidatorNumberExceedsMax + return command.ErrValidatorNumberExceedsMax } return nil } func (p *genesisParams) isValidatorNumberValid() bool { - return uint64(len(p.ibftValidators)) <= p.maxNumValidators + return p.ibftValidators == nil || uint64(p.ibftValidators.Len()) <= p.maxNumValidators } func (p *genesisParams) initIBFTExtraData() { @@ -191,13 +222,22 @@ func (p *genesisParams) initIBFTExtraData() { return } - ibftExtra := &ibft.IstanbulExtra{ - Validators: p.ibftValidators, - ProposerSeal: []byte{}, - CommittedSeal: [][]byte{}, + var committedSeal signer.Seals + + switch p.ibftValidatorType { + case validators.ECDSAValidatorType: + committedSeal = new(signer.SerializedSeal) + case validators.BLSValidatorType: + committedSeal = new(signer.AggregatedSeal) + } + + ibftExtra := &signer.IstanbulExtra{ + Validators: p.ibftValidators, + ProposerSeal: []byte{}, + CommittedSeals: committedSeal, } - p.extraData = make([]byte, ibft.IstanbulExtraVanity) + p.extraData = make([]byte, signer.IstanbulExtraVanity) p.extraData = ibftExtra.MarshalRLPTo(p.extraData) } @@ -211,19 +251,20 @@ func (p *genesisParams) initConsensusEngineConfig() { } if p.isPos { - p.initIBFTEngineMap(ibft.PoS) + p.initIBFTEngineMap(fork.PoS) return } - p.initIBFTEngineMap(ibft.PoA) + p.initIBFTEngineMap(fork.PoA) } -func (p *genesisParams) initIBFTEngineMap(mechanism ibft.MechanismType) { +func (p *genesisParams) initIBFTEngineMap(ibftType fork.IBFTType) { p.consensusEngineConfig = map[string]interface{}{ string(server.IBFTConsensus): map[string]interface{}{ - "type": mechanism, - "epochSize": p.epochSize, + fork.KeyType: ibftType, + fork.KeyValidatorType: p.ibftValidatorType, + ibft.KeyEpochSize: p.epochSize, }, } } @@ -288,7 +329,8 @@ func (p *genesisParams) shouldPredeployStakingSC() bool { } func (p *genesisParams) predeployStakingSC() (*chain.GenesisAccount, error) { - stakingAccount, predeployErr := stakingHelper.PredeployStakingSC(p.ibftValidators, + stakingAccount, predeployErr := stakingHelper.PredeployStakingSC( + p.ibftValidators, stakingHelper.PredeployParams{ MinValidatorCount: p.minNumValidators, MaxValidatorCount: p.maxNumValidators, diff --git a/command/genesis/utils.go b/command/genesis/utils.go index 0a5c4fa6ad..ca8c0b4969 100644 --- a/command/genesis/utils.go +++ b/command/genesis/utils.go @@ -2,15 +2,11 @@ package genesis import ( "fmt" - "io/ioutil" "os" - "path/filepath" "strings" "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/consensus/ibft" - "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" ) @@ -85,43 +81,3 @@ func fillPremineMap( return nil } - -// getValidatorsFromPrefixPath extracts the addresses of the validators based on the directory -// prefix. It scans the directories for validator private keys and compiles a list of addresses -func getValidatorsFromPrefixPath(prefix string) ([]types.Address, error) { - validators := make([]types.Address, 0) - - files, err := ioutil.ReadDir(".") - if err != nil { - return nil, err - } - - for _, file := range files { - path := file.Name() - - if !file.IsDir() { - continue - } - - if !strings.HasPrefix(path, prefix) { - continue - } - - // try to read key from the filepath/consensus/ path - possibleConsensusPath := filepath.Join(path, "consensus", ibft.IbftKeyName) - - // check if path exists - if _, err := os.Stat(possibleConsensusPath); os.IsNotExist(err) { - continue - } - - priv, err := crypto.GenerateOrReadPrivateKey(possibleConsensusPath) - if err != nil { - return nil, err - } - - validators = append(validators, crypto.PubKeyToAddress(&priv.PublicKey)) - } - - return validators, nil -} diff --git a/command/ibft/propose/ibft_propose.go b/command/ibft/propose/ibft_propose.go index 3d2b253190..3c0b60c332 100644 --- a/command/ibft/propose/ibft_propose.go +++ b/command/ibft/propose/ibft_propose.go @@ -32,6 +32,13 @@ func setFlags(cmd *cobra.Command) { "the address of the account to be voted for", ) + cmd.Flags().StringVar( + ¶ms.rawBLSPublicKey, + blsFlag, + "", + "the BLS Public Key of the account to be voted for", + ) + cmd.Flags().StringVar( ¶ms.vote, voteFlag, diff --git a/command/ibft/propose/params.go b/command/ibft/propose/params.go index 35fa8f4823..1db40125ea 100644 --- a/command/ibft/propose/params.go +++ b/command/ibft/propose/params.go @@ -2,18 +2,22 @@ package propose import ( "context" + "encoding/hex" "errors" - - ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" + "fmt" + "strings" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" + ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" ) const ( voteFlag = "vote" addressFlag = "addr" + blsFlag = "bls" ) const ( @@ -31,10 +35,12 @@ var ( ) type proposeParams struct { - addressRaw string + addressRaw string + rawBLSPublicKey string - vote string - address types.Address + vote string + address types.Address + blsPublicKey []byte } func (p *proposeParams) getRequiredFlags() []string { @@ -53,6 +59,18 @@ func (p *proposeParams) validateFlags() error { } func (p *proposeParams) initRawParams() error { + if err := p.initAddress(); err != nil { + return err + } + + if err := p.initBLSPublicKey(); err != nil { + return err + } + + return nil +} + +func (p *proposeParams) initAddress() error { p.address = types.Address{} if err := p.address.UnmarshalText([]byte(p.addressRaw)); err != nil { return errInvalidAddressFormat @@ -61,6 +79,25 @@ func (p *proposeParams) initRawParams() error { return nil } +func (p *proposeParams) initBLSPublicKey() error { + if p.rawBLSPublicKey == "" { + return nil + } + + blsPubkeyBytes, err := hex.DecodeString(strings.TrimPrefix(p.rawBLSPublicKey, "0x")) + if err != nil { + return fmt.Errorf("failed to parse BLS Public Key: %w", err) + } + + if _, err := crypto.UnmarshalBLSPublicKey(blsPubkeyBytes); err != nil { + return err + } + + p.blsPublicKey = blsPubkeyBytes + + return nil +} + func isValidVoteType(vote string) bool { return vote == authVote || vote == dropVote } @@ -73,10 +110,7 @@ func (p *proposeParams) proposeCandidate(grpcAddress string) error { if _, err := ibftClient.Propose( context.Background(), - &ibftOp.Candidate{ - Address: p.address.String(), - Auth: p.vote == authVote, - }, + p.getCandidate(), ); err != nil { return err } @@ -84,6 +118,19 @@ func (p *proposeParams) proposeCandidate(grpcAddress string) error { return nil } +func (p *proposeParams) getCandidate() *ibftOp.Candidate { + res := &ibftOp.Candidate{ + Address: p.address.String(), + Auth: p.vote == authVote, + } + + if p.blsPublicKey != nil { + res.BlsPubkey = p.blsPublicKey + } + + return res +} + func (p *proposeParams) getResult() command.CommandResult { return &IBFTProposeResult{ Address: p.address.String(), diff --git a/command/ibft/snapshot/ibft_snapshot.go b/command/ibft/snapshot/ibft_snapshot.go index b23c4fe206..f60e940f4d 100644 --- a/command/ibft/snapshot/ibft_snapshot.go +++ b/command/ibft/snapshot/ibft_snapshot.go @@ -37,5 +37,12 @@ func runCommand(cmd *cobra.Command, _ []string) { return } - outputter.SetCommandResult(params.getResult()) + result, err := newIBFTSnapshotResult(params.snapshot) + if err != nil { + outputter.SetError(err) + + return + } + + outputter.SetCommandResult(result) } diff --git a/command/ibft/snapshot/params.go b/command/ibft/snapshot/params.go index 3a5a6192ec..21042f73f8 100644 --- a/command/ibft/snapshot/params.go +++ b/command/ibft/snapshot/params.go @@ -3,7 +3,6 @@ package snapshot import ( "context" - "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" ) @@ -53,7 +52,3 @@ func (p *snapshotParams) getSnapshotRequest() *ibftOp.SnapshotReq { return req } - -func (p *snapshotParams) getResult() command.CommandResult { - return newIBFTSnapshotResult(p.snapshot) -} diff --git a/command/ibft/snapshot/result.go b/command/ibft/snapshot/result.go index e65c3896dc..e959d18820 100644 --- a/command/ibft/snapshot/result.go +++ b/command/ibft/snapshot/result.go @@ -7,6 +7,7 @@ import ( "github.com/0xPolygon/polygon-edge/command/helper" ibftHelper "github.com/0xPolygon/polygon-edge/command/ibft/helper" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" + "github.com/0xPolygon/polygon-edge/validators" ) type IBFTSnapshotVote struct { @@ -16,18 +17,18 @@ type IBFTSnapshotVote struct { } type IBFTSnapshotResult struct { - Number uint64 `json:"number"` - Hash string `json:"hash"` - Votes []IBFTSnapshotVote `json:"votes"` - Validators []string `json:"validators"` + Number uint64 `json:"number"` + Hash string `json:"hash"` + Votes []IBFTSnapshotVote `json:"votes"` + Validators []validators.Validator `json:"validators"` } -func newIBFTSnapshotResult(resp *ibftOp.Snapshot) *IBFTSnapshotResult { +func newIBFTSnapshotResult(resp *ibftOp.Snapshot) (*IBFTSnapshotResult, error) { res := &IBFTSnapshotResult{ Number: resp.Number, Hash: resp.Hash, Votes: make([]IBFTSnapshotVote, len(resp.Votes)), - Validators: make([]string, len(resp.Validators)), + Validators: make([]validators.Validator, len(resp.Validators)), } for i, v := range resp.Votes { @@ -36,11 +37,29 @@ func newIBFTSnapshotResult(resp *ibftOp.Snapshot) *IBFTSnapshotResult { res.Votes[i].Vote = ibftHelper.BoolToVote(v.Auth) } + var ( + validatorType validators.ValidatorType + err error + ) + for i, v := range resp.Validators { - res.Validators[i] = v.Address + if validatorType, err = validators.ParseValidatorType(v.Type); err != nil { + return nil, err + } + + validator, err := validators.NewValidatorFromType(validatorType) + if err != nil { + return nil, err + } + + if err := validator.SetFromBytes(v.Data); err != nil { + return nil, err + } + + res.Validators[i] = validator } - return res + return res, nil } func (r *IBFTSnapshotResult) GetOutput() string { @@ -94,7 +113,7 @@ func (r *IBFTSnapshotResult) writeValidatorData(buffer *bytes.Buffer) { if numValidators > 0 { validators[0] = "ADDRESS" for i, d := range r.Validators { - validators[i+1] = d + validators[i+1] = d.String() } } diff --git a/command/ibft/switch/ibft_switch.go b/command/ibft/switch/ibft_switch.go index 3c2d0e1c2c..759ccb442b 100644 --- a/command/ibft/switch/ibft_switch.go +++ b/command/ibft/switch/ibft_switch.go @@ -5,6 +5,7 @@ import ( "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" + "github.com/0xPolygon/polygon-edge/validators" "github.com/spf13/cobra" ) @@ -37,33 +38,68 @@ func setFlags(cmd *cobra.Command) { "the new IBFT type [PoA, PoS]", ) - cmd.Flags().StringVar( - ¶ms.deploymentRaw, - deploymentFlag, - "", - "the height to deploy the contract in PoS", - ) + { + // switch block height + cmd.Flags().StringVar( + ¶ms.deploymentRaw, + deploymentFlag, + "", + "the height to deploy the contract in PoS", + ) + + cmd.Flags().StringVar( + ¶ms.fromRaw, + fromFlag, + "", + "the height to switch the new type", + ) + } + // Validator Configurations cmd.Flags().StringVar( - ¶ms.fromRaw, - fromFlag, - "", - "the height to switch the new type", + ¶ms.rawIBFTValidatorType, + command.IBFTValidatorTypeFlag, + string(validators.BLSValidatorType), + "the type of validators in IBFT", ) - cmd.Flags().StringVar( - ¶ms.minValidatorCountRaw, - minValidatorCount, - "", - "the minimum number of validators in the validator set for PoS", - ) + { + // PoA Configuration + cmd.Flags().StringVar( + ¶ms.ibftValidatorPrefixPath, + command.IBFTValidatorPrefixFlag, + "", + "prefix path for validator folder directory. "+ + "Needs to be present if ibft-validator is omitted", + ) + + cmd.Flags().StringArrayVar( + ¶ms.ibftValidatorsRaw, + command.IBFTValidatorFlag, + []string{}, + "addresses to be used as IBFT validators, can be used multiple times. "+ + "Needs to be present if ibft-validators-prefix-path is omitted", + ) + + cmd.MarkFlagsMutuallyExclusive(command.IBFTValidatorPrefixFlag, command.IBFTValidatorFlag) + } - cmd.Flags().StringVar( - ¶ms.maxValidatorCountRaw, - maxValidatorCount, - "", - "the maximum number of validators in the validator set for PoS", - ) + { + // PoS Configuration + cmd.Flags().StringVar( + ¶ms.minValidatorCountRaw, + minValidatorCount, + "", + "the minimum number of validators in the validator set for PoS", + ) + + cmd.Flags().StringVar( + ¶ms.maxValidatorCountRaw, + maxValidatorCount, + "", + "the maximum number of validators in the validator set for PoS", + ) + } } func runPreRun(_ *cobra.Command, _ []string) error { diff --git a/command/ibft/switch/params.go b/command/ibft/switch/params.go index b504b6d398..2926008ad0 100644 --- a/command/ibft/switch/params.go +++ b/command/ibft/switch/params.go @@ -8,9 +8,10 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/consensus/ibft" + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" ) const ( @@ -23,7 +24,11 @@ const ( ) var ( - ErrFromPositive = errors.New(`"from" must be positive number`) + ErrFromPositive = errors.New(`"from" must be positive number`) + ErrIBFTConfigNotFound = errors.New(`"ibft" config doesn't exist in "engine" of genesis.json'`) + ErrSameIBFTAndValidatorType = errors.New("cannot specify same IBFT type and validator type as the last fork") + ErrLessFromThanLastFrom = errors.New(`"from" must be greater than the beginning height of last fork`) + ErrInvalidValidatorsUpdateHeight = errors.New(`cannot specify a less height than 2 for validators update`) ) var ( @@ -31,20 +36,31 @@ var ( ) type switchParams struct { - typeRaw string - fromRaw string - deploymentRaw string - maxValidatorCountRaw string - minValidatorCountRaw string - genesisPath string + genesisPath string + typeRaw string + ibftType fork.IBFTType - mechanismType ibft.MechanismType + // height + deploymentRaw string deployment *uint64 + fromRaw string from uint64 - genesisConfig *chain.Chain - maxValidatorCount *uint64 - minValidatorCount *uint64 + rawIBFTValidatorType string + ibftValidatorType validators.ValidatorType + + // PoA + ibftValidatorPrefixPath string + ibftValidatorsRaw []string + ibftValidators validators.Validators + + // PoS + maxValidatorCountRaw string + maxValidatorCount *uint64 + minValidatorCountRaw string + minValidatorCount *uint64 + + genesisConfig *chain.Chain } func (p *switchParams) getRequiredFlags() []string { @@ -59,6 +75,10 @@ func (p *switchParams) initRawParams() error { return err } + if err := p.initIBFTValidatorType(); err != nil { + return err + } + if err := p.initDeployment(); err != nil { return err } @@ -67,6 +87,14 @@ func (p *switchParams) initRawParams() error { return err } + if err := p.initPoAConfig(); err != nil { + return err + } + + if err := p.initPoSConfig(); err != nil { + return err + } + if err := p.initChain(); err != nil { return err } @@ -75,22 +103,36 @@ func (p *switchParams) initRawParams() error { } func (p *switchParams) initMechanismType() error { - mechanismType, err := ibft.ParseType(p.typeRaw) + ibftType, err := fork.ParseIBFTType(p.typeRaw) if err != nil { return fmt.Errorf("unable to parse mechanism type: %w", err) } - p.mechanismType = mechanismType + p.ibftType = ibftType + + return nil +} + +func (p *switchParams) initIBFTValidatorType() error { + if p.rawIBFTValidatorType == "" { + return nil + } + + var err error + + if p.ibftValidatorType, err = validators.ParseValidatorType(p.rawIBFTValidatorType); err != nil { + return err + } return nil } func (p *switchParams) initDeployment() error { if p.deploymentRaw != "" { - if p.mechanismType != ibft.PoS { + if p.ibftType != fork.PoS { return fmt.Errorf( "doesn't support contract deployment in %s", - string(p.mechanismType), + string(p.ibftType), ) } @@ -105,14 +147,83 @@ func (p *switchParams) initDeployment() error { p.deployment = &d } - if p.minValidatorCountRaw != "" { - if p.mechanismType != ibft.PoS { + return nil +} + +func (p *switchParams) initPoAConfig() error { + if p.ibftType != fork.PoA { + return nil + } + + p.ibftValidators = validators.NewValidatorSetFromType(p.ibftValidatorType) + + if err := p.setValidatorSetFromPrefixPath(); err != nil { + return err + } + + if err := p.setValidatorSetFromCli(); err != nil { + return err + } + + // Validate if validator number exceeds max number + if uint64(p.ibftValidators.Len()) > common.MaxSafeJSInt { + return command.ErrValidatorNumberExceedsMax + } + + return nil +} + +func (p *switchParams) setValidatorSetFromPrefixPath() error { + if p.ibftValidatorPrefixPath == "" { + return nil + } + + validators, err := command.GetValidatorsFromPrefixPath( + p.ibftValidatorPrefixPath, + p.ibftValidatorType, + ) + if err != nil { + return fmt.Errorf("failed to read from prefix: %w", err) + } + + if err := p.ibftValidators.Merge(validators); err != nil { + return err + } + + return nil +} + +// setValidatorSetFromCli sets validator set from cli command +func (p *switchParams) setValidatorSetFromCli() error { + if len(p.ibftValidatorsRaw) == 0 { + return nil + } + + newSet, err := validators.ParseValidators(p.ibftValidatorType, p.ibftValidatorsRaw) + if err != nil { + return err + } + + if err = p.ibftValidators.Merge(newSet); err != nil { + return err + } + + return nil +} + +func (p *switchParams) initPoSConfig() error { + if p.ibftType != fork.PoS { + if p.minValidatorCountRaw != "" || p.maxValidatorCountRaw != "" { return fmt.Errorf( "doesn't support min validator count in %s", - string(p.mechanismType), + string(p.ibftType), ) } + return nil + } + + if p.minValidatorCountRaw != "" { value, err := types.ParseUint64orHex(&p.minValidatorCountRaw) if err != nil { return fmt.Errorf( @@ -125,13 +236,6 @@ func (p *switchParams) initDeployment() error { } if p.maxValidatorCountRaw != "" { - if p.mechanismType != ibft.PoS { - return fmt.Errorf( - "doesn't support max validator count in %s", - string(p.mechanismType), - ) - } - value, err := types.ParseUint64orHex(&p.maxValidatorCountRaw) if err != nil { return fmt.Errorf( @@ -143,11 +247,7 @@ func (p *switchParams) initDeployment() error { p.maxValidatorCount = &value } - if err := p.validateMinMaxValidatorNumber(); err != nil { - return err - } - - return nil + return p.validateMinMaxValidatorNumber() } func (p *switchParams) validateMinMaxValidatorNumber() error { @@ -205,9 +305,11 @@ func (p *switchParams) initChain() error { func (p *switchParams) updateGenesisConfig() error { return appendIBFTForks( p.genesisConfig, - p.mechanismType, + p.ibftType, + p.ibftValidatorType, p.from, p.deployment, + p.ibftValidators, p.maxValidatorCount, p.minValidatorCount, ) @@ -232,9 +334,10 @@ func (p *switchParams) overrideGenesisConfig() error { func (p *switchParams) getResult() command.CommandResult { result := &IBFTSwitchResult{ - Chain: p.genesisPath, - Type: p.mechanismType, - From: common.JSONNumber{Value: p.from}, + Chain: p.genesisPath, + Type: p.ibftType, + ValidatorType: p.ibftValidatorType, + From: common.JSONNumber{Value: p.from}, } if p.deployment != nil { @@ -258,39 +361,54 @@ func (p *switchParams) getResult() command.CommandResult { func appendIBFTForks( cc *chain.Chain, - mechanismType ibft.MechanismType, + ibftType fork.IBFTType, + validatorType validators.ValidatorType, from uint64, deployment *uint64, + // PoA + validators validators.Validators, + // PoS maxValidatorCount *uint64, minValidatorCount *uint64, ) error { ibftConfig, ok := cc.Params.Engine["ibft"].(map[string]interface{}) if !ok { - return errors.New(`"ibft" setting doesn't exist in "engine" of genesis.json'`) + return ErrIBFTConfigNotFound } - ibftForks, err := ibft.GetIBFTForks(ibftConfig) + ibftForks, err := fork.GetIBFTForks(ibftConfig) if err != nil { return err } - lastFork := &ibftForks[len(ibftForks)-1] - if mechanismType == lastFork.Type { - return errors.New(`cannot specify same IBFT type to the last fork`) + lastFork := ibftForks[len(ibftForks)-1] + + if (ibftType == lastFork.Type) && + (validatorType == lastFork.ValidatorType) { + return ErrSameIBFTAndValidatorType } if from <= lastFork.From.Value { - return errors.New(`"from" must be greater than the beginning height of last fork`) + return ErrLessFromThanLastFrom + } + + if ibftType == fork.PoA && validators != nil && from <= 1 { + // can't update validators at block 0 + return ErrInvalidValidatorsUpdateHeight } lastFork.To = &common.JSONNumber{Value: from - 1} - newFork := ibft.IBFTFork{ - Type: mechanismType, - From: common.JSONNumber{Value: from}, + newFork := fork.IBFTFork{ + Type: ibftType, + ValidatorType: validatorType, + From: common.JSONNumber{Value: from}, } - if mechanismType == ibft.PoS { + switch ibftType { + case fork.PoA: + newFork.Validators = validators + case fork.PoS: if deployment != nil { newFork.Deployment = &common.JSONNumber{Value: *deployment} } @@ -304,7 +422,7 @@ func appendIBFTForks( } } - ibftForks = append(ibftForks, newFork) + ibftForks = append(ibftForks, &newFork) ibftConfig["types"] = ibftForks // remove leftover config diff --git a/command/ibft/switch/result.go b/command/ibft/switch/result.go index e830822c29..afd4c07f6f 100644 --- a/command/ibft/switch/result.go +++ b/command/ibft/switch/result.go @@ -5,17 +5,19 @@ import ( "fmt" "github.com/0xPolygon/polygon-edge/command/helper" - "github.com/0xPolygon/polygon-edge/consensus/ibft" + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/validators" ) type IBFTSwitchResult struct { - Chain string `json:"chain"` - Type ibft.MechanismType `json:"type"` - From common.JSONNumber `json:"from"` - Deployment *common.JSONNumber `json:"deployment,omitempty"` - MaxValidatorCount common.JSONNumber `json:"maxValidatorCount"` - MinValidatorCount common.JSONNumber `json:"minValidatorCount"` + Chain string `json:"chain"` + Type fork.IBFTType `json:"type"` + ValidatorType validators.ValidatorType `json:"validator_type"` + From common.JSONNumber `json:"from"` + Deployment *common.JSONNumber `json:"deployment,omitempty"` + MaxValidatorCount common.JSONNumber `json:"maxValidatorCount"` + MinValidatorCount common.JSONNumber `json:"minValidatorCount"` } func (r *IBFTSwitchResult) GetOutput() string { @@ -26,14 +28,21 @@ func (r *IBFTSwitchResult) GetOutput() string { outputs := []string{ fmt.Sprintf("Chain|%s", r.Chain), fmt.Sprintf("Type|%s", r.Type), + fmt.Sprintf("ValidatorType|%s", r.ValidatorType), } + if r.Deployment != nil { outputs = append(outputs, fmt.Sprintf("Deployment|%d", r.Deployment.Value)) } outputs = append(outputs, fmt.Sprintf("From|%d", r.From.Value)) - outputs = append(outputs, fmt.Sprintf("MaxValidatorCount|%d", r.MaxValidatorCount.Value)) - outputs = append(outputs, fmt.Sprintf("MinValidatorCount|%d", r.MinValidatorCount.Value)) + + if r.Type == fork.PoS { + outputs = append(outputs, + fmt.Sprintf("MaxValidatorCount|%d", r.MaxValidatorCount.Value), + fmt.Sprintf("MinValidatorCount|%d", r.MinValidatorCount.Value), + ) + } buffer.WriteString(helper.FormatKV(outputs)) buffer.WriteString("\n") diff --git a/command/loadbot/generator/transfer_generator.go b/command/loadbot/generator/transfer_generator.go index 3b9fb920fc..51b0802292 100644 --- a/command/loadbot/generator/transfer_generator.go +++ b/command/loadbot/generator/transfer_generator.go @@ -42,7 +42,7 @@ func (tg *TransferGenerator) GetExampleTransaction() (*types.Transaction, error) } func (tg *TransferGenerator) generateReceiver() error { - key, err := crypto.GenerateKey() + key, err := crypto.GenerateECDSAKey() if err != nil { return err } diff --git a/command/loadbot/generators.go b/command/loadbot/generators.go index 97684f63f7..fa6ac3ca09 100644 --- a/command/loadbot/generators.go +++ b/command/loadbot/generators.go @@ -41,7 +41,7 @@ func extractSenderAccount(address types.Address) (*Account, error) { privateKeyRaw := os.Getenv("LOADBOT_" + address.String()) privateKeyRaw = strings.TrimPrefix(privateKeyRaw, "0x") - privateKey, err := crypto.BytesToPrivateKey([]byte(privateKeyRaw)) + privateKey, err := crypto.BytesToECDSAPrivateKey([]byte(privateKeyRaw)) if err != nil { return nil, fmt.Errorf("failed to extract ECDSA private key from bytes: %w", err) diff --git a/command/secrets/init/helper.go b/command/secrets/init/helper.go new file mode 100644 index 0000000000..a44f891591 --- /dev/null +++ b/command/secrets/init/helper.go @@ -0,0 +1,77 @@ +package init + +import ( + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/network" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/libp2p/go-libp2p-core/peer" +) + +// loadValidatorAddress loads ECDSA key by SecretsManager and returns validator address +func loadValidatorAddress(secretsManager secrets.SecretsManager) (types.Address, error) { + if !secretsManager.HasSecret(secrets.ValidatorKey) { + return types.ZeroAddress, nil + } + + encodedKey, err := secretsManager.GetSecret(secrets.ValidatorKey) + if err != nil { + return types.ZeroAddress, err + } + + privateKey, err := crypto.BytesToECDSAPrivateKey(encodedKey) + if err != nil { + return types.ZeroAddress, err + } + + return crypto.PubKeyToAddress(&privateKey.PublicKey), nil +} + +// loadValidatorAddress loads BLS key by SecretsManager and returns BLS Public Key +func loadBLSPublicKey(secretsManager secrets.SecretsManager) (string, error) { + if !secretsManager.HasSecret(secrets.ValidatorBLSKey) { + return "", nil + } + + encodedKey, err := secretsManager.GetSecret(secrets.ValidatorBLSKey) + if err != nil { + return "", err + } + + secretKey, err := crypto.BytesToBLSSecretKey(encodedKey) + if err != nil { + return "", err + } + + pubkeyBytes, err := crypto.BLSSecretKeyToPubkeyBytes(secretKey) + if err != nil { + return "", err + } + + return hex.EncodeToHex(pubkeyBytes), nil +} + +// loadNodeID loads Libp2p key by SecretsManager and returns Node ID +func loadNodeID(secretsManager secrets.SecretsManager) (string, error) { + if !secretsManager.HasSecret(secrets.NetworkKey) { + return "", nil + } + + encodedKey, err := secretsManager.GetSecret(secrets.NetworkKey) + if err != nil { + return "", err + } + + parsedKey, err := network.ParseLibp2pKey(encodedKey) + if err != nil { + return "", err + } + + nodeID, err := peer.IDFromPrivateKey(parsedKey) + if err != nil { + return "", err + } + + return nodeID.String(), nil +} diff --git a/command/secrets/init/params.go b/command/secrets/init/params.go index 313068e15e..2836a233b4 100644 --- a/command/secrets/init/params.go +++ b/command/secrets/init/params.go @@ -1,20 +1,19 @@ package init import ( - "crypto/ecdsa" "errors" "github.com/0xPolygon/polygon-edge/command" - "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/helper" - libp2pCrypto "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" ) const ( dataDirFlag = "data-dir" configFlag = "config" + ecdsaFlag = "ecdsa" + blsFlag = "bls" + networkFlag = "network" ) var ( @@ -28,16 +27,14 @@ var ( ) type initParams struct { - dataDir string - configPath string + dataDir string + configPath string + generatesECDSA bool + generatesBLS bool + generatesNetwork bool secretsManager secrets.SecretsManager secretsConfig *secrets.SecretsManagerConfig - - validatorPrivateKey *ecdsa.PrivateKey - networkingPrivateKey libp2pCrypto.PrivKey - - nodeID peer.ID } func (ip *initParams) validateFlags() error { @@ -137,41 +134,51 @@ func (ip *initParams) initLocalSecretsManager() error { } func (ip *initParams) initValidatorKey() error { - validatorKey, err := helper.InitValidatorKey(ip.secretsManager) - if err != nil { - return err + var err error + + if ip.generatesECDSA { + if _, err = helper.InitECDSAValidatorKey(ip.secretsManager); err != nil { + return err + } } - ip.validatorPrivateKey = validatorKey + if ip.generatesBLS { + if _, err = helper.InitBLSValidatorKey(ip.secretsManager); err != nil { + return err + } + } return nil } func (ip *initParams) initNetworkingKey() error { - networkingKey, err := helper.InitNetworkingPrivateKey(ip.secretsManager) - if err != nil { - return err + if ip.generatesNetwork { + if _, err := helper.InitNetworkingPrivateKey(ip.secretsManager); err != nil { + return err + } } - ip.networkingPrivateKey = networkingKey - - return ip.initNodeID() + return nil } -func (ip *initParams) initNodeID() error { - nodeID, err := peer.IDFromPrivateKey(ip.networkingPrivateKey) - if err != nil { - return err - } +// getResult gets keys from secret manager and return result to display +func (ip *initParams) getResult() (command.CommandResult, error) { + var ( + res = &SecretsInitResult{} + err error + ) - ip.nodeID = nodeID + if res.Address, err = loadValidatorAddress(ip.secretsManager); err != nil { + return nil, err + } - return nil -} + if res.BLSPubkey, err = loadBLSPublicKey(ip.secretsManager); err != nil { + return nil, err + } -func (ip *initParams) getResult() command.CommandResult { - return &SecretsInitResult{ - Address: crypto.PubKeyToAddress(&ip.validatorPrivateKey.PublicKey), - NodeID: ip.nodeID.String(), + if res.NodeID, err = loadNodeID(ip.secretsManager); err != nil { + return nil, err } + + return res, nil } diff --git a/command/secrets/init/result.go b/command/secrets/init/result.go index 6a14cdb3e7..18e7d2a2ca 100644 --- a/command/secrets/init/result.go +++ b/command/secrets/init/result.go @@ -9,18 +9,32 @@ import ( ) type SecretsInitResult struct { - Address types.Address `json:"address"` - NodeID string `json:"node_id"` + Address types.Address `json:"address"` + BLSPubkey string `json:"bls_pubkey"` + NodeID string `json:"node_id"` } func (r *SecretsInitResult) GetOutput() string { var buffer bytes.Buffer + vals := make([]string, 0, 3) + + vals = append( + vals, + fmt.Sprintf("Public key (address)|%s", r.Address.String()), + ) + + if r.BLSPubkey != "" { + vals = append( + vals, + fmt.Sprintf("BLS Public key|%s", r.BLSPubkey), + ) + } + + vals = append(vals, fmt.Sprintf("Node ID|%s", r.NodeID)) + buffer.WriteString("\n[SECRETS INIT]\n") - buffer.WriteString(helper.FormatKV([]string{ - fmt.Sprintf("Public key (address)|%s", r.Address), - fmt.Sprintf("Node ID|%s", r.NodeID), - })) + buffer.WriteString(helper.FormatKV(vals)) buffer.WriteString("\n") return buffer.String() diff --git a/command/secrets/init/secrets_init.go b/command/secrets/init/secrets_init.go index 1fc2aaab5a..8e2ac9fe59 100644 --- a/command/secrets/init/secrets_init.go +++ b/command/secrets/init/secrets_init.go @@ -36,6 +36,27 @@ func setFlags(cmd *cobra.Command) { ) cmd.MarkFlagsMutuallyExclusive(dataDirFlag, configFlag) + + cmd.Flags().BoolVar( + ¶ms.generatesECDSA, + ecdsaFlag, + true, + "the flag indicating whether new ECDSA key is created", + ) + + cmd.Flags().BoolVar( + ¶ms.generatesNetwork, + networkFlag, + true, + "the flag indicating whether new Network key is created", + ) + + cmd.Flags().BoolVar( + ¶ms.generatesBLS, + blsFlag, + true, + "the flag indicating whether new BLS key is created", + ) } func runPreRun(_ *cobra.Command, _ []string) error { @@ -52,5 +73,12 @@ func runCommand(cmd *cobra.Command, _ []string) { return } - outputter.SetCommandResult(params.getResult()) + res, err := params.getResult() + if err != nil { + outputter.SetError(err) + + return + } + + outputter.SetCommandResult(res) } diff --git a/command/server/server.go b/command/server/server.go index 8971a32e13..3cf1752ace 100644 --- a/command/server/server.go +++ b/command/server/server.go @@ -4,12 +4,11 @@ import ( "fmt" "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/command/server/config" "github.com/0xPolygon/polygon-edge/command/server/export" - "github.com/spf13/cobra" - - "github.com/0xPolygon/polygon-edge/command/helper" "github.com/0xPolygon/polygon-edge/server" + "github.com/spf13/cobra" ) func GetCommand() *cobra.Command { @@ -223,6 +222,7 @@ func setFlags(cmd *cobra.Command) { ) setLegacyFlags(cmd) + setDevFlags(cmd) } diff --git a/consensus/consensus.go b/consensus/consensus.go index 1841bc91a1..afb55e5154 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -28,8 +28,8 @@ type Consensus interface { // GetBlockCreator retrieves the block creator (or signer) given the block header GetBlockCreator(header *types.Header) (types.Address, error) - // PreStateCommit a hook to be called before finalizing state transition on inserting block - PreStateCommit(header *types.Header, txn *state.Transition) error + // PreCommitState a hook to be called before finalizing state transition on inserting block + PreCommitState(header *types.Header, txn *state.Transition) error // GetSyncProgression retrieves the current sync progression, if any GetSyncProgression() *progress.Progression diff --git a/consensus/dev/dev.go b/consensus/dev/dev.go index 210eee981f..10179d01bf 100644 --- a/consensus/dev/dev.go +++ b/consensus/dev/dev.go @@ -223,11 +223,11 @@ func (d *Dev) ProcessHeaders(headers []*types.Header) error { } func (d *Dev) GetBlockCreator(header *types.Header) (types.Address, error) { - return header.Miner, nil + return types.BytesToAddress(header.Miner), nil } -// PreStateCommit a hook to be called before finalizing state transition on inserting block -func (d *Dev) PreStateCommit(_header *types.Header, _txn *state.Transition) error { +// PreCommitState a hook to be called before finalizing state transition on inserting block +func (d *Dev) PreCommitState(_header *types.Header, _txn *state.Transition) error { return nil } diff --git a/consensus/dummy/dummy.go b/consensus/dummy/dummy.go index f9aad4e3b0..be044361bb 100644 --- a/consensus/dummy/dummy.go +++ b/consensus/dummy/dummy.go @@ -57,11 +57,11 @@ func (d *Dummy) ProcessHeaders(headers []*types.Header) error { } func (d *Dummy) GetBlockCreator(header *types.Header) (types.Address, error) { - return header.Miner, nil + return types.BytesToAddress(header.Miner), nil } -// PreStateCommit a hook to be called before finalizing state transition on inserting block -func (d *Dummy) PreStateCommit(_header *types.Header, _txn *state.Transition) error { +// PreCommitState a hook to be called before finalizing state transition on inserting block +func (d *Dummy) PreCommitState(_header *types.Header, _txn *state.Transition) error { return nil } diff --git a/consensus/ibft/consensus_backend.go b/consensus/ibft/consensus_backend.go index 1d73ae1a85..0822bf9d60 100644 --- a/consensus/ibft/consensus_backend.go +++ b/consensus/ibft/consensus_backend.go @@ -2,10 +2,12 @@ package ibft import ( "fmt" + "math" "time" "github.com/0xPolygon/go-ibft/messages" "github.com/0xPolygon/polygon-edge/consensus" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/types" ) @@ -26,14 +28,7 @@ func (i *backendIBFT) BuildProposal(blockNumber uint64) []byte { return nil } - snap := i.getSnapshot(latestBlockNumber) - if snap == nil { - i.logger.Error("cannot find snapshot", "num", latestBlockNumber) - - return nil - } - - block, err := i.buildBlock(snap, latestHeader) + block, err := i.buildBlock(latestHeader) if err != nil { i.logger.Error("cannot build block", "num", blockNumber, "err", err) @@ -54,13 +49,14 @@ func (i *backendIBFT) InsertBlock( return } - seals := make([][]byte, len(committedSeals)) - for idx := range committedSeals { - seals[idx] = committedSeals[idx].Signature + committedSealsMap := make(map[types.Address][]byte, len(committedSeals)) + + for _, cm := range committedSeals { + committedSealsMap[types.BytesToAddress(cm.Signer)] = cm.Signature } // Push the committed seals to the header - header, err := writeCommittedSeals(newBlock.Header, seals) + header, err := i.currentSigner.WriteCommittedSeals(newBlock.Header, committedSealsMap) if err != nil { i.logger.Error("cannot write committed seals", "err", err) @@ -76,52 +72,67 @@ func (i *backendIBFT) InsertBlock( return } - if err := i.runHook(InsertBlockHook, header.Number, header.Number); err != nil { - i.logger.Error("cannot run hook", "name", string(InsertBlockHook), "err", err) - - return - } - i.updateMetrics(newBlock) i.logger.Info( "block committed", "number", newBlock.Number(), "hash", newBlock.Hash(), - "validators", len(i.activeValidatorSet), + "validation_type", i.currentSigner.Type(), + "validators", i.currentValidators.Len(), "committed", len(committedSeals), ) + if err := i.currentHooks.PostInsertBlock(newBlock); err != nil { + i.logger.Error( + "failed to call PostInsertBlock hook", + "height", newBlock.Number(), + "hash", newBlock.Hash(), + "err", err, + ) + + return + } + // after the block has been written we reset the txpool so that // the old transactions are removed i.txpool.ResetWithHeaders(newBlock.Header) } func (i *backendIBFT) ID() []byte { - return i.validatorKeyAddr.Bytes() + return i.currentSigner.Address().Bytes() } func (i *backendIBFT) MaximumFaultyNodes() uint64 { - return uint64(i.activeValidatorSet.MaxFaultyNodes()) + return uint64(CalcMaxFaultyNodes(i.currentValidators)) } func (i *backendIBFT) Quorum(blockNumber uint64) uint64 { - var ( - validators = i.activeValidatorSet - quorumFn = i.quorumSize(blockNumber) - ) + validators, err := i.forkManager.GetValidators(blockNumber) + if err != nil { + i.logger.Error( + "failed to get validators when calculation quorum", + "height", blockNumber, + "err", err, + ) + + // return Math.MaxInt32 to prevent overflow when casting to int in go-ibft package + return math.MaxInt32 + } + + quorumFn := i.quorumSize(blockNumber) return uint64(quorumFn(validators)) } // buildBlock builds the block, based on the passed in snapshot and parent header -func (i *backendIBFT) buildBlock(snap *Snapshot, parent *types.Header) (*types.Block, error) { +func (i *backendIBFT) buildBlock(parent *types.Header) (*types.Block, error) { header := &types.Header{ ParentHash: parent.Hash, Number: parent.Number + 1, - Miner: types.Address{}, + Miner: types.ZeroAddress.Bytes(), Nonce: types.Nonce{}, - MixHash: IstanbulDigest, + MixHash: signer.IstanbulDigest, // this is required because blockchain needs difficulty to organize blocks and forks Difficulty: parent.Number + 1, StateRoot: types.EmptyRootHash, // this avoids needing state for now @@ -137,29 +148,28 @@ func (i *backendIBFT) buildBlock(snap *Snapshot, parent *types.Header) (*types.B header.GasLimit = gasLimit - if hookErr := i.runHook(CandidateVoteHook, header.Number, &candidateVoteHookParams{ - header: header, - snap: snap, - }); hookErr != nil { - i.logger.Error(fmt.Sprintf("Unable to run hook %s, %v", CandidateVoteHook, hookErr)) + if err := i.currentHooks.ModifyHeader(header, i.currentSigner.Address()); err != nil { + return nil, err } // set the timestamp header.Timestamp = uint64(time.Now().Unix()) - // we need to include in the extra field the current set of validators - putIbftExtraValidators(header, snap.Set) + parentCommittedSeals, err := i.extractParentCommittedSeals(parent) + if err != nil { + return nil, err + } - transition, err := i.executor.BeginTxn(parent.StateRoot, header, i.validatorKeyAddr) + i.currentSigner.InitIBFTExtra(header, i.currentValidators, parentCommittedSeals) + + transition, err := i.executor.BeginTxn(parent.StateRoot, header, i.currentSigner.Address()) if err != nil { return nil, err } - // If the mechanism is PoS -> build a regular block if it's not an end-of-epoch block - // If the mechanism is PoA -> always build a regular block, regardless of epoch txs := i.writeTransactions(gasLimit, header.Number, transition) - if err := i.PreStateCommit(header, transition); err != nil { + if err := i.PreCommitState(header, transition); err != nil { return nil, err } @@ -175,7 +185,7 @@ func (i *backendIBFT) buildBlock(snap *Snapshot, parent *types.Header) (*types.B }) // write the seal of the block after all the fields are completed - header, err = writeProposerSeal(i.validatorKey, block.Header) + header, err = i.currentSigner.WriteProposerSeal(header) if err != nil { return nil, err } @@ -216,7 +226,7 @@ func (i *backendIBFT) writeTransactions( ) (executed []*types.Transaction) { executed = make([]*types.Transaction, 0) - if !i.shouldWriteTransactions(blockNumber) { + if !i.currentHooks.ShouldWriteTransactions(blockNumber) { return } @@ -321,3 +331,31 @@ func (i *backendIBFT) writeTransaction( return &txExeResult{tx, success}, true } + +// extractCommittedSeals extracts CommittedSeals from header +func (i *backendIBFT) extractCommittedSeals( + header *types.Header, +) (signer.Seals, error) { + signer, err := i.forkManager.GetSigner(header.Number) + if err != nil { + return nil, err + } + + extra, err := signer.GetIBFTExtra(header) + if err != nil { + return nil, err + } + + return extra.CommittedSeals, nil +} + +// extractParentCommittedSeals extracts ParentCommittedSeals from header +func (i *backendIBFT) extractParentCommittedSeals( + header *types.Header, +) (signer.Seals, error) { + if header.Number == 0 { + return nil, nil + } + + return i.extractCommittedSeals(header) +} diff --git a/consensus/ibft/extra.go b/consensus/ibft/extra.go deleted file mode 100644 index 0cdee219a0..0000000000 --- a/consensus/ibft/extra.go +++ /dev/null @@ -1,178 +0,0 @@ -package ibft - -import ( - "fmt" - - "github.com/0xPolygon/polygon-edge/types" - "github.com/umbracle/fastrlp" -) - -var ( - // IstanbulDigest represents a hash of "Istanbul practical byzantine fault tolerance" - // to identify whether the block is from Istanbul consensus engine - IstanbulDigest = types.StringToHash("0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365") - - // IstanbulExtraVanity represents a fixed number of extra-data bytes reserved for proposer vanity - IstanbulExtraVanity = 32 - - // IstanbulExtraSeal represents the fixed number of extra-data bytes reserved for proposer seal - IstanbulExtraSeal = 65 -) - -var zeroBytes = make([]byte, 32) - -// putIbftExtraValidators is a helper method that adds validators to the extra field in the header -func putIbftExtraValidators(h *types.Header, validators []types.Address) { - // Pad zeros to the right up to istanbul vanity - extra := h.ExtraData - if len(extra) < IstanbulExtraVanity { - extra = append(extra, zeroBytes[:IstanbulExtraVanity-len(extra)]...) - } else { - extra = extra[:IstanbulExtraVanity] - } - - ibftExtra := &IstanbulExtra{ - Validators: validators, - ProposerSeal: []byte{}, - CommittedSeal: [][]byte{}, - } - - extra = ibftExtra.MarshalRLPTo(extra) - h.ExtraData = extra -} - -// PutIbftExtra sets the extra data field in the header to the passed in istanbul extra data -func PutIbftExtra(h *types.Header, istanbulExtra *IstanbulExtra) error { - // Pad zeros to the right up to istanbul vanity - extra := h.ExtraData - if len(extra) < IstanbulExtraVanity { - extra = append(extra, zeroBytes[:IstanbulExtraVanity-len(extra)]...) - } else { - extra = extra[:IstanbulExtraVanity] - } - - data := istanbulExtra.MarshalRLPTo(nil) - extra = append(extra, data...) - h.ExtraData = extra - - return nil -} - -// getIbftExtra returns the istanbul extra data field from the passed in header -func getIbftExtra(h *types.Header) (*IstanbulExtra, error) { - if len(h.ExtraData) < IstanbulExtraVanity { - return nil, fmt.Errorf("wrong extra size: %d", len(h.ExtraData)) - } - - data := h.ExtraData[IstanbulExtraVanity:] - extra := &IstanbulExtra{} - - if err := extra.UnmarshalRLP(data); err != nil { - return nil, err - } - - return extra, nil -} - -// IstanbulExtra defines the structure of the extra field for Istanbul -type IstanbulExtra struct { - Validators []types.Address - ProposerSeal []byte - CommittedSeal [][]byte -} - -// MarshalRLPTo defines the marshal function wrapper for IstanbulExtra -func (i *IstanbulExtra) MarshalRLPTo(dst []byte) []byte { - return types.MarshalRLPTo(i.MarshalRLPWith, dst) -} - -// MarshalRLPWith defines the marshal function implementation for IstanbulExtra -func (i *IstanbulExtra) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { - vv := ar.NewArray() - - // Validators - vals := ar.NewArray() - for _, a := range i.Validators { - vals.Set(ar.NewBytes(a.Bytes())) - } - - vv.Set(vals) - - // ProposerSeal - if len(i.ProposerSeal) == 0 { - vv.Set(ar.NewNull()) - } else { - vv.Set(ar.NewBytes(i.ProposerSeal)) - } - - // CommittedSeal - if len(i.CommittedSeal) == 0 { - vv.Set(ar.NewNullArray()) - } else { - committed := ar.NewArray() - for _, a := range i.CommittedSeal { - if len(a) == 0 { - vv.Set(ar.NewNull()) - } else { - committed.Set(ar.NewBytes(a)) - } - } - vv.Set(committed) - } - - return vv -} - -// UnmarshalRLP defines the unmarshal function wrapper for IstanbulExtra -func (i *IstanbulExtra) UnmarshalRLP(input []byte) error { - return types.UnmarshalRlp(i.UnmarshalRLPFrom, input) -} - -// UnmarshalRLPFrom defines the unmarshal implementation for IstanbulExtra -func (i *IstanbulExtra) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error { - elems, err := v.GetElems() - if err != nil { - return err - } - - if len(elems) < 3 { - return fmt.Errorf("incorrect number of elements to decode istambul extra, expected 3 but found %d", len(elems)) - } - - // Validators - { - vals, err := elems[0].GetElems() - if err != nil { - return fmt.Errorf("list expected for validators") - } - i.Validators = make([]types.Address, len(vals)) - for indx, val := range vals { - if err = val.GetAddr(i.Validators[indx][:]); err != nil { - return err - } - } - } - - // ProposerSeal - { - if i.ProposerSeal, err = elems[1].GetBytes(i.ProposerSeal); err != nil { - return err - } - } - - // Committed - { - vals, err := elems[2].GetElems() - if err != nil { - return fmt.Errorf("list expected for committed") - } - i.CommittedSeal = make([][]byte, len(vals)) - for indx, val := range vals { - if i.CommittedSeal[indx], err = val.GetBytes(i.CommittedSeal[indx]); err != nil { - return err - } - } - } - - return nil -} diff --git a/consensus/ibft/extra_test.go b/consensus/ibft/extra_test.go deleted file mode 100644 index 4ab13b1cfb..0000000000 --- a/consensus/ibft/extra_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package ibft - -import ( - "reflect" - "testing" - - "github.com/0xPolygon/polygon-edge/types" -) - -func TestExtraEncoding(t *testing.T) { - seal1 := types.StringToHash("1").Bytes() - - cases := []struct { - extra []byte - data *IstanbulExtra - }{ - { - data: &IstanbulExtra{ - Validators: []types.Address{ - types.StringToAddress("1"), - }, - ProposerSeal: seal1, - CommittedSeal: [][]byte{ - seal1, - }, - }, - }, - } - - for _, c := range cases { - data := c.data.MarshalRLPTo(nil) - - ii := &IstanbulExtra{} - if err := ii.UnmarshalRLP(data); err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(c.data, ii) { - t.Fatal("bad") - } - } -} diff --git a/consensus/ibft/fork/fork.go b/consensus/ibft/fork/fork.go new file mode 100644 index 0000000000..cf6a4c4090 --- /dev/null +++ b/consensus/ibft/fork/fork.go @@ -0,0 +1,157 @@ +package fork + +import ( + "encoding/json" + "errors" + + "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/validators" +) + +const ( + // Keys in IBFT Configuration + KeyType = "type" + KeyTypes = "types" + KeyValidatorType = "validator_type" +) + +var ( + ErrUndefinedIBFTConfig = errors.New("IBFT config is not defined") +) + +// IBFT Fork represents setting in params.engine.ibft of genesis.json +type IBFTFork struct { + Type IBFTType `json:"type"` + ValidatorType validators.ValidatorType `json:"validator_type"` + Deployment *common.JSONNumber `json:"deployment,omitempty"` + From common.JSONNumber `json:"from"` + To *common.JSONNumber `json:"to,omitempty"` + + // PoA + Validators validators.Validators `json:"validators,omitempty"` + + // PoS + MaxValidatorCount *common.JSONNumber `json:"maxValidatorCount,omitempty"` + MinValidatorCount *common.JSONNumber `json:"minValidatorCount,omitempty"` +} + +func (f *IBFTFork) UnmarshalJSON(data []byte) error { + raw := struct { + Type IBFTType `json:"type"` + ValidatorType *validators.ValidatorType `json:"validator_type,omitempty"` + Deployment *common.JSONNumber `json:"deployment,omitempty"` + From common.JSONNumber `json:"from"` + To *common.JSONNumber `json:"to,omitempty"` + Validators interface{} `json:"validators,omitempty"` + MaxValidatorCount *common.JSONNumber `json:"maxValidatorCount,omitempty"` + MinValidatorCount *common.JSONNumber `json:"minValidatorCount,omitempty"` + }{} + + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + f.Type = raw.Type + f.Deployment = raw.Deployment + f.From = raw.From + f.To = raw.To + f.MaxValidatorCount = raw.MaxValidatorCount + f.MinValidatorCount = raw.MinValidatorCount + + f.ValidatorType = validators.ECDSAValidatorType + if raw.ValidatorType != nil { + f.ValidatorType = *raw.ValidatorType + } + + if raw.Validators == nil { + return nil + } + + f.Validators = validators.NewValidatorSetFromType(f.ValidatorType) + + validatorsBytes, err := json.Marshal(raw.Validators) + if err != nil { + return err + } + + if err := json.Unmarshal(validatorsBytes, f.Validators); err != nil { + return err + } + + return nil +} + +// GetIBFTForks returns IBFT fork configurations from chain config +func GetIBFTForks(ibftConfig map[string]interface{}) (IBFTForks, error) { + // no fork, only specifying IBFT type in chain config + if originalType, ok := ibftConfig[KeyType].(string); ok { + typ, err := ParseIBFTType(originalType) + if err != nil { + return nil, err + } + + validatorType := validators.ECDSAValidatorType + + if rawValType, ok := ibftConfig[KeyValidatorType].(string); ok { + if validatorType, err = validators.ParseValidatorType(rawValType); err != nil { + return nil, err + } + } + + return IBFTForks{ + { + Type: typ, + Deployment: nil, + ValidatorType: validatorType, + From: common.JSONNumber{Value: 0}, + To: nil, + }, + }, nil + } + + // with forks + if types, ok := ibftConfig[KeyTypes].([]interface{}); ok { + bytes, err := json.Marshal(types) + if err != nil { + return nil, err + } + + var forks IBFTForks + if err := json.Unmarshal(bytes, &forks); err != nil { + return nil, err + } + + return forks, nil + } + + return nil, ErrUndefinedIBFTConfig +} + +type IBFTForks []*IBFTFork + +// getByFork returns the fork in which the given height is +// it doesn't use binary search for now because number of IBFTFork is not so many +func (fs *IBFTForks) getFork(height uint64) *IBFTFork { + for idx := len(*fs) - 1; idx >= 0; idx-- { + fork := (*fs)[idx] + + if fork.From.Value <= height && (fork.To == nil || height <= fork.To.Value) { + return fork + } + } + + return nil +} + +// filterByType returns new list of IBFTFork whose type matches with the given type +func (fs *IBFTForks) filterByType(ibftType IBFTType) IBFTForks { + filteredForks := make(IBFTForks, 0) + + for _, fork := range *fs { + if fork.Type == ibftType { + filteredForks = append(filteredForks, fork) + } + } + + return filteredForks +} diff --git a/consensus/ibft/fork/fork_test.go b/consensus/ibft/fork/fork_test.go new file mode 100644 index 0000000000..3c8cf358cb --- /dev/null +++ b/consensus/ibft/fork/fork_test.go @@ -0,0 +1,333 @@ +package fork + +import ( + "encoding/json" + "errors" + "fmt" + "testing" + + "github.com/0xPolygon/polygon-edge/helper/common" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +func TestIBFTForkUnmarshalJSON(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + data string + expected *IBFTFork + err error + }{ + { + name: "should parse without validator type and validators", + data: fmt.Sprintf(`{ + "type": "%s", + "from": %d + }`, PoA, 0), + expected: &IBFTFork{ + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: nil, + Validators: nil, + MaxValidatorCount: nil, + MinValidatorCount: nil, + }, + }, + { + name: "should parse without validators", + data: fmt.Sprintf(`{ + "type": "%s", + "from": %d, + "to": %d, + "maxValidatorCount": %d, + "MinValidatorCount": %d + }`, PoS, 10, 15, 100, 1), + expected: &IBFTFork{ + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 10}, + To: &common.JSONNumber{Value: 15}, + Validators: nil, + MaxValidatorCount: &common.JSONNumber{Value: 100}, + MinValidatorCount: &common.JSONNumber{Value: 1}, + }, + }, + { + name: "should parse without validators", + data: fmt.Sprintf(`{ + "type": "%s", + "validator_type": "%s", + "validators": [ + { + "Address": "%s" + }, + { + "Address": "%s" + } + ], + "from": %d, + "to": %d + }`, + PoA, validators.ECDSAValidatorType, + types.StringToAddress("1"), types.StringToAddress("2"), + 16, 20, + ), + expected: &IBFTFork{ + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 16}, + To: &common.JSONNumber{Value: 20}, + Validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + validators.NewECDSAValidator(types.StringToAddress("2")), + ), + MaxValidatorCount: nil, + MinValidatorCount: nil, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + fork := &IBFTFork{} + + err := json.Unmarshal([]byte(test.data), fork) + + testHelper.AssertErrorMessageContains(t, test.err, err) + + assert.Equal(t, test.expected, fork) + }) + } +} + +func TestGetIBFTForks(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + config map[string]interface{} + res IBFTForks + err error + }{ + { + name: "should return error if invalid type is set in type", + config: map[string]interface{}{ + "type": "invalid", + }, + res: nil, + err: errors.New("invalid IBFT type invalid"), + }, + { + name: "should return a single fork for ECDSA if IBFTConfig has type but it doesn't have validator type", + config: map[string]interface{}{ + "type": "PoA", + }, + res: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + Deployment: nil, + From: common.JSONNumber{Value: 0}, + To: nil, + }, + }, + err: nil, + }, + { + name: "should return a single fork for ECDSA if IBFTConfig has type and validator type", + config: map[string]interface{}{ + "type": "PoS", + "validator_type": "bls", + }, + res: IBFTForks{ + { + Type: PoS, + ValidatorType: validators.BLSValidatorType, + Deployment: nil, + From: common.JSONNumber{Value: 0}, + To: nil, + }, + }, + err: nil, + }, + { + name: "should return multiple forks", + config: map[string]interface{}{ + "types": []interface{}{ + map[string]interface{}{ + "type": "PoA", + "validator_type": "ecdsa", + "from": 0, + "to": 10, + }, + map[string]interface{}{ + "type": "PoA", + "validator_type": "bls", + "from": 11, + }, + }, + }, + res: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + Deployment: nil, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + Type: PoA, + ValidatorType: validators.BLSValidatorType, + Deployment: nil, + From: common.JSONNumber{Value: 11}, + To: nil, + }, + }, + err: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := GetIBFTForks(test.config) + + assert.Equal( + t, + test.res, + res, + ) + + testHelper.AssertErrorMessageContains( + t, + test.err, + err, + ) + }) + } +} + +func TestIBFTForks_getFork(t *testing.T) { + t.Parallel() + + forks := IBFTForks{ + { + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + From: common.JSONNumber{Value: 11}, + To: &common.JSONNumber{Value: 50}, + }, + { + From: common.JSONNumber{Value: 51}, + }, + } + + tests := []struct { + name string + height uint64 + expected *IBFTFork + }{ + { + name: "should return the first fork if height is 0", + height: 0, + expected: forks[0], + }, + { + name: "should return the first fork if height is 1", + height: 1, + expected: forks[0], + }, + { + name: "should return the first fork if height is 10", + height: 10, + expected: forks[0], + }, + { + name: "should return the first fork if height is 11", + height: 11, + expected: forks[1], + }, + { + name: "should return the first fork if height is 50", + height: 50, + expected: forks[1], + }, + { + name: "should return the first fork if height is 51", + height: 51, + expected: forks[2], + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + forks.getFork(test.height), + ) + }) + } +} + +func TestIBFTForks_filterByType(t *testing.T) { + t.Parallel() + + forks := IBFTForks{ + { + Type: PoA, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + Type: PoS, + From: common.JSONNumber{Value: 11}, + To: &common.JSONNumber{Value: 20}, + }, + { + Type: PoA, + From: common.JSONNumber{Value: 21}, + To: &common.JSONNumber{Value: 30}, + }, + { + Type: PoS, + From: common.JSONNumber{Value: 31}, + }, + } + + assert.Equal( + t, + IBFTForks{ + forks[0], + forks[2], + }, + forks.filterByType(PoA), + ) + + assert.Equal( + t, + IBFTForks{ + forks[1], + forks[3], + }, + forks.filterByType(PoS), + ) +} diff --git a/consensus/ibft/fork/helper.go b/consensus/ibft/fork/helper.go new file mode 100644 index 0000000000..6f5c95ecd5 --- /dev/null +++ b/consensus/ibft/fork/helper.go @@ -0,0 +1,63 @@ +package fork + +import ( + "encoding/json" + "io/ioutil" + "os" + + "github.com/0xPolygon/polygon-edge/validators/store/snapshot" +) + +// loadSnapshotMetadata loads Metadata from file +func loadSnapshotMetadata(path string) (*snapshot.SnapshotMetadata, error) { + var meta *snapshot.SnapshotMetadata + if err := readDataStore(path, &meta); err != nil { + return nil, err + } + + return meta, nil +} + +// loadSnapshots loads Snapshots from file +func loadSnapshots(path string) ([]*snapshot.Snapshot, error) { + snaps := []*snapshot.Snapshot{} + if err := readDataStore(path, &snaps); err != nil { + return nil, err + } + + return snaps, nil +} + +// readDataStore attempts to read the specific file from file storage +// return nil if the file doesn't exist +func readDataStore(path string, obj interface{}) error { + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil + } + + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + if err := json.Unmarshal(data, obj); err != nil { + return err + } + + return nil +} + +// writeDataStore attempts to write the specific file to file storage +func writeDataStore(path string, obj interface{}) error { + data, err := json.Marshal(obj) + if err != nil { + return err + } + + //nolint: gosec + if err := ioutil.WriteFile(path, data, 0755); err != nil { + return err + } + + return nil +} diff --git a/consensus/ibft/fork/helper_test.go b/consensus/ibft/fork/helper_test.go new file mode 100644 index 0000000000..eebc9a9d35 --- /dev/null +++ b/consensus/ibft/fork/helper_test.go @@ -0,0 +1,256 @@ +package fork + +import ( + "encoding/json" + "errors" + "os" + "path" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/0xPolygon/polygon-edge/validators/store/snapshot" + "github.com/stretchr/testify/assert" +) + +var ( + sampleJSON = `{"Hello":"World"}` + sampleMap = map[string]interface{}{ + "Hello": "World", + } +) + +func createTestTempDirectory(t *testing.T) string { + t.Helper() + + path, err := os.MkdirTemp("", "temp") + if err != nil { + t.Logf("failed to create temp directory, err=%+v", err) + + t.FailNow() + } + + t.Cleanup(func() { + os.RemoveAll(path) + }) + + return path +} + +func Test_loadSnapshotMetadata(t *testing.T) { + t.Parallel() + + t.Run("should return error if the file doesn't exist", func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + + res, err := loadSnapshotMetadata(filePath) + + assert.NoError(t, err) + assert.Nil(t, res) + }) + + t.Run("should load metadata", func(t *testing.T) { + t.Parallel() + + metadata := &snapshot.SnapshotMetadata{ + LastBlock: 100, + } + + fileData, err := json.Marshal(metadata) + assert.NoError(t, err) + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + assert.NoError(t, os.WriteFile(filePath, fileData, 0600)) + + res, err := loadSnapshotMetadata(filePath) + + assert.NoError( + t, + err, + ) + + assert.Equal( + t, + metadata, + res, + ) + }) +} + +func Test_loadSnapshots(t *testing.T) { + t.Parallel() + + t.Run("should return error if the file doesn't exist", func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + + res, err := loadSnapshots(filePath) + + assert.NoError(t, err) + assert.Equal(t, []*snapshot.Snapshot{}, res) + }) + + t.Run("should load metadata", func(t *testing.T) { + t.Parallel() + + snapshots := []*snapshot.Snapshot{ + { + Number: 10, + Hash: types.BytesToHash(crypto.Keccak256([]byte{0x10})).String(), + Set: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + ), + Votes: []*store.Vote{ + { + Candidate: validators.NewECDSAValidator(types.StringToAddress("2")), + Validator: types.StringToAddress("1"), + Authorize: true, + }, + }, + }, + } + + fileData, err := json.Marshal(snapshots) + assert.NoError(t, err) + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + assert.NoError(t, os.WriteFile(filePath, fileData, 0600)) + + res, err := loadSnapshots(filePath) + + assert.NoError( + t, + err, + ) + + assert.Equal( + t, + snapshots, + res, + ) + }) +} + +func Test_readDataStore(t *testing.T) { + t.Parallel() + + t.Run("should return error if the file doesn't exist", func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + var data interface{} + + assert.Equal( + t, + nil, + readDataStore(filePath, data), + ) + }) + + t.Run("should return error if the content is not json", func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + + assert.NoError( + t, + os.WriteFile(filePath, []byte("hello: world"), 0600), + ) + + data := map[string]interface{}{} + + assert.IsType( + t, + &json.SyntaxError{}, + readDataStore(filePath, data), + ) + }) + + t.Run("should read and map to object", func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + + assert.NoError( + t, + os.WriteFile(filePath, []byte(sampleJSON), 0600), + ) + + data := map[string]interface{}{} + + assert.NoError( + t, + readDataStore(filePath, &data), + ) + + assert.Equal( + t, + sampleMap, + data, + ) + }) +} + +func Test_writeDataStore(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + data interface{} + expectedStoredData string + expectedErr error + }{ + { + name: "should return error if json.Marshal failed", + data: func() {}, + expectedStoredData: "", + expectedErr: errors.New("json: unsupported type: func()"), + }, + { + name: "should return error if WriteFile failed", + data: map[string]interface{}{ + "Hello": "World", + }, + expectedStoredData: sampleJSON, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + filePath := path.Join(dirPath, "test.dat") + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + writeDataStore(filePath, test.data), + ) + + readData, _ := os.ReadFile(filePath) + + assert.Equal( + t, + test.expectedStoredData, + string(readData), + ) + }) + } +} diff --git a/consensus/ibft/fork/hookregister.go b/consensus/ibft/fork/hookregister.go new file mode 100644 index 0000000000..5d2f291c4a --- /dev/null +++ b/consensus/ibft/fork/hookregister.go @@ -0,0 +1,102 @@ +package fork + +import ( + "github.com/0xPolygon/polygon-edge/consensus/ibft/hook" +) + +// PoAHookRegisterer that registers hooks for PoA mode +type PoAHookRegister struct { + getValidatorsStore func(*IBFTFork) ValidatorStore + poaForks IBFTForks + updateValidatorsForks map[uint64]*IBFTFork +} + +// NewPoAHookRegisterer is a constructor of PoAHookRegister +func NewPoAHookRegisterer( + getValidatorsStore func(*IBFTFork) ValidatorStore, + forks IBFTForks, +) *PoAHookRegister { + poaForks := forks.filterByType(PoA) + + updateValidatorsForks := make(map[uint64]*IBFTFork) + + for _, fork := range poaForks { + if fork.Validators == nil { + continue + } + + updateValidatorsForks[fork.From.Value] = fork + } + + return &PoAHookRegister{ + getValidatorsStore: getValidatorsStore, + poaForks: poaForks, + updateValidatorsForks: updateValidatorsForks, + } +} + +// RegisterHooks registers hooks of PoA for voting and validators updating +func (r *PoAHookRegister) RegisterHooks(hooks *hook.Hooks, height uint64) { + if currentFork := r.poaForks.getFork(height); currentFork != nil { + // in PoA mode currently + validatorStore := r.getValidatorsStore(currentFork) + + registerHeaderModifierHooks(hooks, validatorStore) + } + + // update validators in the end of the last block + if updateValidatorsFork, ok := r.updateValidatorsForks[height+1]; ok { + validatorStore := r.getValidatorsStore(updateValidatorsFork) + + registerUpdateValidatorsHooks( + hooks, + validatorStore, + updateValidatorsFork.Validators, + updateValidatorsFork.From.Value, + ) + } +} + +// PoAHookRegisterer that registers hooks for PoS mode +type PoSHookRegister struct { + posForks IBFTForks + epochSize uint64 + deployContractForks map[uint64]*IBFTFork +} + +// NewPoSHookRegister is a constructor of PoSHookRegister +func NewPoSHookRegister( + forks IBFTForks, + epochSize uint64, +) *PoSHookRegister { + posForks := forks.filterByType(PoS) + + deployContractForks := make(map[uint64]*IBFTFork) + + for _, fork := range posForks { + if fork.Deployment == nil { + continue + } + + deployContractForks[fork.Deployment.Value] = fork + } + + return &PoSHookRegister{ + posForks: posForks, + epochSize: epochSize, + deployContractForks: deployContractForks, + } +} + +// RegisterHooks registers hooks of PoA for additional block verification and contract deployment +func (r *PoSHookRegister) RegisterHooks(hooks *hook.Hooks, height uint64) { + if currentFork := r.posForks.getFork(height); currentFork != nil { + // in PoS mode currently + registerTxInclusionGuardHooks(hooks, r.epochSize) + } + + if deploymentFork, ok := r.deployContractForks[height]; ok { + // deploy or update staking contract in deployment height + registerStakingContractDeploymentHooks(hooks, deploymentFork) + } +} diff --git a/consensus/ibft/fork/hooks.go b/consensus/ibft/fork/hooks.go new file mode 100644 index 0000000000..74d9435d3b --- /dev/null +++ b/consensus/ibft/fork/hooks.go @@ -0,0 +1,136 @@ +package fork + +import ( + "errors" + + "github.com/0xPolygon/polygon-edge/consensus/ibft/hook" + "github.com/0xPolygon/polygon-edge/contracts/staking" + "github.com/0xPolygon/polygon-edge/helper/hex" + stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" +) + +var ( + ErrTxInLastEpochOfBlock = errors.New("block must not have transactions in the last of epoch") +) + +// HeaderModifier is an interface for the struct that modifies block header for additional process +type HeaderModifier interface { + ModifyHeader(*types.Header, types.Address) error + VerifyHeader(*types.Header) error + ProcessHeader(*types.Header) error +} + +// registerHeaderModifierHooks registers hooks to modify header by validator store +func registerHeaderModifierHooks( + hooks *hook.Hooks, + validatorStore store.ValidatorStore, +) { + if modifier, ok := validatorStore.(HeaderModifier); ok { + hooks.ModifyHeaderFunc = modifier.ModifyHeader + hooks.VerifyHeaderFunc = modifier.VerifyHeader + hooks.ProcessHeaderFunc = modifier.ProcessHeader + } +} + +// Updatable is an interface for the struct that updates validators in the middle +type Updatable interface { + // UpdateValidatorSet updates validators forcibly + // in order that new validators are available from the given height + UpdateValidatorSet(validators.Validators, uint64) error +} + +// registerUpdateValidatorsHooks registers hooks to update validators in the middle +func registerUpdateValidatorsHooks( + hooks *hook.Hooks, + validatorStore store.ValidatorStore, + validators validators.Validators, + fromHeight uint64, +) { + if us, ok := validatorStore.(Updatable); ok { + hooks.PostInsertBlockFunc = func(b *types.Block) error { + if fromHeight != b.Number()+1 { + return nil + } + + // update validators if the block height is the one before beginning height + return us.UpdateValidatorSet(validators, fromHeight) + } + } +} + +// registerPoSVerificationHooks registers that hooks to prevent the last epoch block from having transactions +func registerTxInclusionGuardHooks(hooks *hook.Hooks, epochSize uint64) { + isLastEpoch := func(height uint64) bool { + return height > 0 && height%epochSize == 0 + } + + hooks.ShouldWriteTransactionFunc = func(height uint64) bool { + return !isLastEpoch(height) + } + + hooks.VerifyBlockFunc = func(block *types.Block) error { + if isLastEpoch(block.Number()) && len(block.Transactions) > 0 { + return ErrTxInLastEpochOfBlock + } + + return nil + } +} + +// registerStakingContractDeploymentHooks registers hooks +// to deploy or update staking contract +func registerStakingContractDeploymentHooks( + hooks *hook.Hooks, + fork *IBFTFork, +) { + hooks.PreCommitStateFunc = func(header *types.Header, txn *state.Transition) error { + // safe check + if header.Number != fork.Deployment.Value { + return nil + } + + if txn.AccountExists(staking.AddrStakingContract) { + // update bytecode of deployed contract + codeBytes, err := hex.DecodeHex(stakingHelper.StakingSCBytecode) + if err != nil { + return err + } + + return txn.SetCodeDirectly(staking.AddrStakingContract, codeBytes) + } else { + // deploy contract + contractState, err := stakingHelper.PredeployStakingSC( + fork.Validators, + getPreDeployParams(fork), + ) + + if err != nil { + return err + } + + return txn.SetAccountDirectly(staking.AddrStakingContract, contractState) + } + } +} + +// getPreDeployParams returns PredeployParams for Staking Contract from IBFTFork +func getPreDeployParams(fork *IBFTFork) stakingHelper.PredeployParams { + params := stakingHelper.PredeployParams{ + MinValidatorCount: stakingHelper.MinValidatorCount, + MaxValidatorCount: stakingHelper.MaxValidatorCount, + } + + if fork.MinValidatorCount != nil { + params.MinValidatorCount = fork.MinValidatorCount.Value + } + + if fork.MaxValidatorCount != nil { + params.MaxValidatorCount = fork.MaxValidatorCount.Value + } + + return params +} diff --git a/consensus/ibft/fork/hooks_test.go b/consensus/ibft/fork/hooks_test.go new file mode 100644 index 0000000000..1d283187e2 --- /dev/null +++ b/consensus/ibft/fork/hooks_test.go @@ -0,0 +1,400 @@ +package fork + +import ( + "errors" + "testing" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/consensus/ibft/hook" + "github.com/0xPolygon/polygon-edge/contracts/staking" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/common" + stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" + "github.com/0xPolygon/polygon-edge/state" + itrie "github.com/0xPolygon/polygon-edge/state/immutable-trie" + "github.com/0xPolygon/polygon-edge/state/runtime/evm" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" +) + +type mockHeaderModifierStore struct { + store.ValidatorStore + + ModifyHeaderFunc func(*types.Header, types.Address) error + VerifyHeaderFunc func(*types.Header) error + ProcessHeaderFunc func(*types.Header) error +} + +func (m *mockHeaderModifierStore) ModifyHeader(header *types.Header, addr types.Address) error { + return m.ModifyHeaderFunc(header, addr) +} + +func (m *mockHeaderModifierStore) VerifyHeader(header *types.Header) error { + return m.VerifyHeaderFunc(header) +} + +func (m *mockHeaderModifierStore) ProcessHeader(header *types.Header) error { + return m.ProcessHeaderFunc(header) +} + +type mockUpdatableStore struct { + store.ValidatorStore + + UpdateValidatorStoreFunc func(validators.Validators, uint64) error +} + +func (m *mockUpdatableStore) UpdateValidatorSet(validators validators.Validators, height uint64) error { + return m.UpdateValidatorStoreFunc(validators, height) +} + +func Test_registerHeaderModifierHooks(t *testing.T) { + t.Parallel() + + t.Run("should do nothing if validator store doesn't implement HeaderModifier", func(t *testing.T) { + t.Parallel() + + type invalidValidatorStoreMock struct { + store.ValidatorStore + } + + hooks := &hook.Hooks{} + mockStore := &invalidValidatorStoreMock{} + + registerHeaderModifierHooks(hooks, mockStore) + + assert.Equal( + t, + &hook.Hooks{}, + hooks, + ) + }) + + t.Run("should register functions to the hooks", func(t *testing.T) { + t.Parallel() + + var ( + header = &types.Header{ + Number: 100, + Hash: types.BytesToHash(crypto.Keccak256([]byte{0x10, 0x0})), + } + addr = types.StringToAddress("1") + + err1 = errors.New("error 1") + err2 = errors.New("error 1") + err3 = errors.New("error 1") + ) + + hooks := &hook.Hooks{} + mockStore := &mockHeaderModifierStore{ + ModifyHeaderFunc: func(h *types.Header, a types.Address) error { + assert.Equal(t, header, h) + assert.Equal(t, addr, a) + + return err1 + }, + VerifyHeaderFunc: func(h *types.Header) error { + assert.Equal(t, header, h) + + return err2 + }, + ProcessHeaderFunc: func(h *types.Header) error { + assert.Equal(t, header, h) + + return err3 + }, + } + + registerHeaderModifierHooks(hooks, mockStore) + + assert.Nil(t, hooks.ShouldWriteTransactionFunc) + assert.Nil(t, hooks.VerifyBlockFunc) + assert.Nil(t, hooks.PreCommitStateFunc) + assert.Nil(t, hooks.PostInsertBlockFunc) + + assert.Equal( + t, + hooks.ModifyHeader(header, addr), + err1, + ) + assert.Equal( + t, + hooks.VerifyHeader(header), + err2, + ) + assert.Equal( + t, + hooks.ProcessHeader(header), + err3, + ) + }) +} + +func Test_registerUpdateValidatorsHooks(t *testing.T) { + t.Parallel() + + var ( + vals = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + validators.NewECDSAValidator(types.StringToAddress("2")), + ) + ) + + t.Run("should do nothing if validator store doesn't implement Updatable", func(t *testing.T) { + t.Parallel() + + type invalidValidatorStoreMock struct { + store.ValidatorStore + } + + hooks := &hook.Hooks{} + mockStore := &invalidValidatorStoreMock{} + + registerUpdateValidatorsHooks(hooks, mockStore, vals, 0) + + assert.Equal( + t, + &hook.Hooks{}, + hooks, + ) + }) + + t.Run("should register UpdateValidatorSet to the hooks", func(t *testing.T) { + t.Parallel() + + var ( + fromHeight uint64 = 10 + err = errors.New("test") + + block = &types.Block{ + Header: &types.Header{}, + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + ) + + hooks := &hook.Hooks{} + mockStore := &mockUpdatableStore{ + UpdateValidatorStoreFunc: func(v validators.Validators, h uint64) error { + assert.Equal(t, vals, v) + assert.Equal(t, fromHeight, h) + + return err + }, + } + + registerUpdateValidatorsHooks(hooks, mockStore, vals, fromHeight) + + assert.Nil(t, hooks.ModifyHeaderFunc) + assert.Nil(t, hooks.VerifyHeaderFunc) + assert.Nil(t, hooks.ProcessHeaderFunc) + assert.Nil(t, hooks.ShouldWriteTransactionFunc) + assert.Nil(t, hooks.VerifyBlockFunc) + assert.Nil(t, hooks.PreCommitStateFunc) + + // case 1: the block number is not the one before fromHeight + assert.NoError( + t, + hooks.PostInsertBlockFunc(block), + ) + + // case 2: the block number is the one before fromHeight + block.Header.Number = fromHeight - 1 + + assert.Equal( + t, + hooks.PostInsertBlockFunc(block), + err, + ) + }) +} + +func Test_registerTxInclusionGuardHooks(t *testing.T) { + t.Parallel() + + epochSize := uint64(10) + hooks := &hook.Hooks{} + + registerTxInclusionGuardHooks(hooks, epochSize) + + assert.Nil(t, hooks.ModifyHeaderFunc) + assert.Nil(t, hooks.VerifyHeaderFunc) + assert.Nil(t, hooks.ProcessHeaderFunc) + assert.Nil(t, hooks.PreCommitStateFunc) + assert.Nil(t, hooks.PostInsertBlockFunc) + + var ( + cases = map[uint64]bool{ + 0: true, + epochSize - 1: true, + epochSize: false, + epochSize + 1: true, + epochSize*2 - 1: true, + epochSize * 2: false, + epochSize*2 + 1: true, + } + + blockWithoutTransactions = &types.Block{ + Header: &types.Header{}, + Transactions: []*types.Transaction{}, + } + + blockWithTransactions = &types.Block{ + Header: &types.Header{}, + Transactions: []*types.Transaction{ + { + Nonce: 0, + }, + }, + } + ) + + for h, ok := range cases { + assert.Equal( + t, + ok, + hooks.ShouldWriteTransactions(h), + ) + + blockWithTransactions.Header.Number = h + blockWithoutTransactions.Header.Number = h + + if ok { + assert.NoError(t, hooks.VerifyBlock(blockWithoutTransactions)) + assert.NoError(t, hooks.VerifyBlock(blockWithTransactions)) + } else { + assert.NoError(t, hooks.VerifyBlock(blockWithoutTransactions)) + assert.ErrorIs(t, ErrTxInLastEpochOfBlock, hooks.VerifyBlock(blockWithTransactions)) + } + } +} + +func newTestTransition( + t *testing.T, +) *state.Transition { + t.Helper() + + st := itrie.NewState(itrie.NewMemoryStorage()) + + ex := state.NewExecutor(&chain.Params{ + Forks: chain.AllForksEnabled, + }, st, hclog.NewNullLogger()) + + rootHash := ex.WriteGenesis(nil) + + ex.SetRuntime(evm.NewEVM()) + ex.GetHash = func(h *types.Header) state.GetHashByNumber { + return func(i uint64) types.Hash { + return rootHash + } + } + + transition, err := ex.BeginTxn( + rootHash, + &types.Header{}, + types.ZeroAddress, + ) + assert.NoError(t, err) + + return transition +} + +func Test_registerStakingContractDeploymentHooks(t *testing.T) { + t.Parallel() + + hooks := &hook.Hooks{} + fork := &IBFTFork{ + Deployment: &common.JSONNumber{ + Value: 10, + }, + } + + registerStakingContractDeploymentHooks(hooks, fork) + + assert.Nil(t, hooks.ShouldWriteTransactionFunc) + assert.Nil(t, hooks.ModifyHeaderFunc) + assert.Nil(t, hooks.VerifyHeaderFunc) + assert.Nil(t, hooks.ProcessHeaderFunc) + assert.Nil(t, hooks.PostInsertBlockFunc) + + txn := newTestTransition(t) + + // deployment should not happen + assert.NoError( + t, + hooks.PreCommitState(&types.Header{Number: 5}, txn), + ) + + assert.False( + t, + txn.AccountExists(staking.AddrStakingContract), + ) + + // should deploy contract + assert.NoError( + t, + hooks.PreCommitState(&types.Header{Number: 10}, txn), + ) + + assert.True( + t, + txn.AccountExists(staking.AddrStakingContract), + ) + + // should update only bytecode (if contract is deployed again, it returns error) + assert.NoError( + t, + hooks.PreCommitState(&types.Header{Number: 10}, txn), + ) + + assert.True( + t, + txn.AccountExists(staking.AddrStakingContract), + ) +} + +func Test_getPreDeployParams(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + fork *IBFTFork + params stakingHelper.PredeployParams + }{ + { + name: "should use the given heights", + fork: &IBFTFork{ + MinValidatorCount: &common.JSONNumber{Value: 10}, + MaxValidatorCount: &common.JSONNumber{Value: 20}, + }, + params: stakingHelper.PredeployParams{ + MinValidatorCount: 10, + MaxValidatorCount: 20, + }, + }, + { + name: "should use the default values", + fork: &IBFTFork{}, + params: stakingHelper.PredeployParams{ + MinValidatorCount: stakingHelper.MinValidatorCount, + MaxValidatorCount: stakingHelper.MaxValidatorCount, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.params, + getPreDeployParams(test.fork), + ) + }) + } +} diff --git a/consensus/ibft/fork/manager.go b/consensus/ibft/fork/manager.go new file mode 100644 index 0000000000..4e91e8f84f --- /dev/null +++ b/consensus/ibft/fork/manager.go @@ -0,0 +1,326 @@ +package fork + +import ( + "errors" + + "github.com/0xPolygon/polygon-edge/consensus/ibft/hook" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/0xPolygon/polygon-edge/validators/store/contract" + "github.com/hashicorp/go-hclog" +) + +const ( + loggerName = "fork_manager" + snapshotMetadataFilename = "metadata" + snapshotSnapshotsFilename = "snapshots" +) + +var ( + ErrForkNotFound = errors.New("fork not found") + ErrSignerNotFound = errors.New("signer not found") + ErrValidatorStoreNotFound = errors.New("validator set not found") + ErrKeyManagerNotFound = errors.New("key manager not found") +) + +// ValidatorStore is an interface that ForkManager calls for Validator Store +type ValidatorStore interface { + store.ValidatorStore + // Close defines termination process + Close() error + // GetValidators is a method to return validators at the given height + GetValidators(height, epochSize, forkFrom uint64) (validators.Validators, error) +} + +// HookRegister is an interface that ForkManager calls for hook registrations +type HooksRegister interface { + // RegisterHooks register hooks for the given block height + RegisterHooks(hooks *hook.Hooks, height uint64) +} + +// HooksInterface is an interface of hooks to be called by IBFT +// This interface is referred from fork and ibft package +type HooksInterface interface { + ShouldWriteTransactions(uint64) bool + ModifyHeader(*types.Header, types.Address) error + VerifyHeader(*types.Header) error + VerifyBlock(*types.Block) error + ProcessHeader(*types.Header) error + PreCommitState(*types.Header, *state.Transition) error + PostInsertBlock(*types.Block) error +} + +// ForkManager is the module that has Fork configuration and multiple version of submodules +// and returns the proper submodule at specified height +type ForkManager struct { + logger hclog.Logger + blockchain store.HeaderGetter + executor contract.Executor + secretsManager secrets.SecretsManager + + // configuration + forks IBFTForks + filePath string + epochSize uint64 + + // submodule lookup + keyManagers map[validators.ValidatorType]signer.KeyManager + validatorStores map[store.SourceType]ValidatorStore + hooksRegisters map[IBFTType]HooksRegister +} + +// NewForkManager is a constructor of ForkManager +func NewForkManager( + logger hclog.Logger, + blockchain store.HeaderGetter, + executor contract.Executor, + secretManager secrets.SecretsManager, + filePath string, + epochSize uint64, + ibftConfig map[string]interface{}, +) (*ForkManager, error) { + forks, err := GetIBFTForks(ibftConfig) + if err != nil { + return nil, err + } + + fm := &ForkManager{ + logger: logger.Named(loggerName), + blockchain: blockchain, + executor: executor, + secretsManager: secretManager, + filePath: filePath, + epochSize: epochSize, + forks: forks, + keyManagers: make(map[validators.ValidatorType]signer.KeyManager), + validatorStores: make(map[store.SourceType]ValidatorStore), + hooksRegisters: make(map[IBFTType]HooksRegister), + } + + // Need initialization of signers in the constructor + // because hash calculation is called from blockchain initialization + if err := fm.initializeKeyManagers(); err != nil { + return nil, err + } + + return fm, nil +} + +// Initialize initializes ForkManager on initialization phase +func (m *ForkManager) Initialize() error { + if err := m.initializeValidatorStores(); err != nil { + return err + } + + m.initializeHooksRegisters() + + return nil +} + +// Close calls termination process of submodules +func (m *ForkManager) Close() error { + for _, store := range m.validatorStores { + if err := store.Close(); err != nil { + return err + } + } + + return nil +} + +// GetSigner returns a proper signer at specified height +func (m *ForkManager) GetSigner(height uint64) (signer.Signer, error) { + keyManager, err := m.getKeyManager(height) + if err != nil { + return nil, err + } + + var parentKeyManager signer.KeyManager + + if height > 1 { + if parentKeyManager, err = m.getKeyManager(height - 1); err != nil { + return nil, err + } + } + + return signer.NewSigner( + keyManager, + parentKeyManager, + ), nil +} + +// GetValidatorStore returns a proper validator set at specified height +func (m *ForkManager) GetValidatorStore(height uint64) (ValidatorStore, error) { + fork := m.forks.getFork(height) + if fork == nil { + return nil, ErrForkNotFound + } + + set := m.getValidatorStoreByIBFTFork(fork) + if set == nil { + return nil, ErrValidatorStoreNotFound + } + + return set, nil +} + +// GetValidators returns validators at specified height +func (m *ForkManager) GetValidators(height uint64) (validators.Validators, error) { + fork := m.forks.getFork(height) + if fork == nil { + return nil, ErrForkNotFound + } + + set := m.getValidatorStoreByIBFTFork(fork) + if set == nil { + return nil, ErrValidatorStoreNotFound + } + + return set.GetValidators( + height, + m.epochSize, + fork.From.Value, + ) +} + +// GetHooks returns a hooks at specified height +func (m *ForkManager) GetHooks(height uint64) HooksInterface { + hooks := &hook.Hooks{} + + for _, r := range m.hooksRegisters { + r.RegisterHooks(hooks, height) + } + + return hooks +} + +func (m *ForkManager) getValidatorStoreByIBFTFork(fork *IBFTFork) ValidatorStore { + set, ok := m.validatorStores[ibftTypesToSourceType[fork.Type]] + if !ok { + return nil + } + + return set +} + +func (m *ForkManager) getKeyManager(height uint64) (signer.KeyManager, error) { + fork := m.forks.getFork(height) + if fork == nil { + return nil, ErrForkNotFound + } + + keyManager, ok := m.keyManagers[fork.ValidatorType] + if !ok { + return nil, ErrKeyManagerNotFound + } + + return keyManager, nil +} + +// initializeKeyManagers initialize all key managers based on Fork configuration +func (m *ForkManager) initializeKeyManagers() error { + for _, fork := range m.forks { + if err := m.initializeKeyManager(fork.ValidatorType); err != nil { + return err + } + } + + return nil +} + +// initializeKeyManager initializes the sp +func (m *ForkManager) initializeKeyManager(valType validators.ValidatorType) error { + if _, ok := m.keyManagers[valType]; ok { + return nil + } + + keyManager, err := signer.NewKeyManagerFromType(m.secretsManager, valType) + if err != nil { + return err + } + + m.keyManagers[valType] = keyManager + + return nil +} + +// initializeValidatorStores initializes all validator sets based on Fork configuration +func (m *ForkManager) initializeValidatorStores() error { + for _, fork := range m.forks { + sourceType := ibftTypesToSourceType[fork.Type] + if err := m.initializeValidatorStore(sourceType); err != nil { + return err + } + } + + return nil +} + +// initializeValidatorStore initializes the specified validator set +func (m *ForkManager) initializeValidatorStore(setType store.SourceType) error { + if _, ok := m.validatorStores[setType]; ok { + return nil + } + + var ( + valStore ValidatorStore + err error + ) + + switch setType { + case store.Snapshot: + valStore, err = NewSnapshotValidatorStoreWrapper( + m.logger, + m.blockchain, + m.GetSigner, + m.filePath, + m.epochSize, + ) + case store.Contract: + valStore, err = NewContractValidatorStoreWrapper( + m.logger, + m.blockchain, + m.executor, + m.GetSigner, + ) + } + + if err != nil { + return err + } + + m.validatorStores[setType] = valStore + + return nil +} + +// initializeHooksRegisters initialize all HookRegisters to be used +func (m *ForkManager) initializeHooksRegisters() { + for _, fork := range m.forks { + m.initializeHooksRegister(fork.Type) + } +} + +// initializeHooksRegister initialize HookRegister by IBFTType +func (m *ForkManager) initializeHooksRegister(ibftType IBFTType) { + if _, ok := m.hooksRegisters[ibftType]; ok { + return + } + + switch ibftType { + case PoA: + m.hooksRegisters[PoA] = NewPoAHookRegisterer( + m.getValidatorStoreByIBFTFork, + m.forks, + ) + case PoS: + m.hooksRegisters[PoS] = NewPoSHookRegister( + m.forks, + m.epochSize, + ) + } +} diff --git a/consensus/ibft/fork/manager_test.go b/consensus/ibft/fork/manager_test.go new file mode 100644 index 0000000000..b56bf098eb --- /dev/null +++ b/consensus/ibft/fork/manager_test.go @@ -0,0 +1,926 @@ +package fork + +import ( + "errors" + "path" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/ibft/hook" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/common" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/0xPolygon/polygon-edge/validators/store/snapshot" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" +) + +type mockValidatorStore struct { + store.ValidatorStore + + CloseFunc func() error + GetValidatorsFunc func(uint64, uint64, uint64) (validators.Validators, error) +} + +func (m *mockValidatorStore) Close() error { + return m.CloseFunc() +} + +func (m *mockValidatorStore) GetValidators(height, epoch, from uint64) (validators.Validators, error) { + return m.GetValidatorsFunc(height, epoch, from) +} + +type mockHooksRegister struct { + RegisterHooksFunc func(hooks *hook.Hooks, height uint64) +} + +func (m *mockHooksRegister) RegisterHooks(hooks *hook.Hooks, height uint64) { + m.RegisterHooksFunc(hooks, height) +} + +type mockSecretManager struct { + secrets.SecretsManager + + HasSecretFunc func(name string) bool + GetSecretFunc func(name string) ([]byte, error) +} + +func (m *mockSecretManager) HasSecret(name string) bool { + return m.HasSecretFunc(name) +} + +func (m *mockSecretManager) GetSecret(name string) ([]byte, error) { + return m.GetSecretFunc(name) +} + +func TestNewForkManager(t *testing.T) { + t.Parallel() + + _, ecdsaKeyBytes, err := crypto.GenerateAndEncodeECDSAPrivateKey() + assert.NoError(t, err) + + _, blsKeyBytes, err := crypto.GenerateAndEncodeBLSSecretKey() + assert.NoError(t, err) + + logger := hclog.NewNullLogger() + + t.Run("should return error if ibftConfig is empty", func(t *testing.T) { + t.Parallel() + + _, err := NewForkManager( + logger, + nil, + nil, + nil, + "", + 0, + map[string]interface{}{}, + ) + + assert.ErrorIs(t, ErrUndefinedIBFTConfig, err) + }) + + t.Run("should return error if key manager initialization fails", func(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + + secretManager = &mockSecretManager{ + HasSecretFunc: func(name string) bool { + return true + }, + GetSecretFunc: func(name string) ([]byte, error) { + return nil, errTest + }, + } + ) + + _, err := NewForkManager( + logger, + nil, + nil, + secretManager, + "", + epochSize, + map[string]interface{}{ + "type": "PoS", + "validator_type": "bls", + }, + ) + + assert.ErrorIs(t, errTest, err) + }) + + t.Run("should return error if validator store initialization fails", func(t *testing.T) { + t.Parallel() + + var ( + latestNumber uint64 = 50 + epochSize uint64 = 10 + + blockchain = &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: latestNumber} + }, + GetHeaderByNumberFn: func(u uint64) (*types.Header, bool) { + return nil, false + }, + } + + secretManager = &mockSecretManager{ + HasSecretFunc: func(name string) bool { + assert.Equal(t, secrets.ValidatorKey, name) + + return true + }, + GetSecretFunc: func(name string) ([]byte, error) { + assert.Equal(t, secrets.ValidatorKey, name) + + return ecdsaKeyBytes, nil + }, + } + ) + + dirPath := createTestTempDirectory(t) + + fm, err := NewForkManager( + logger, + blockchain, + nil, + secretManager, + dirPath, + epochSize, + map[string]interface{}{ + "type": "PoA", + "validator_type": "ecdsa", + }, + ) + + assert.NoError(t, err) + testHelper.AssertErrorMessageContains( + t, + errors.New("header at 50 not found"), + fm.Initialize(), + ) + }) + + t.Run("PoA and ECDSA", func(t *testing.T) { + t.Parallel() + + var ( + latestNumber uint64 = 50 + epochSize uint64 = 10 + + metadata = &snapshot.SnapshotMetadata{ + LastBlock: latestNumber, + } + + snapshots = []*snapshot.Snapshot{ + { + Number: latestNumber, + Hash: types.BytesToHash(crypto.Keccak256([]byte{0x10})).String(), + Set: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + ), + Votes: []*store.Vote{ + { + Candidate: validators.NewECDSAValidator(types.StringToAddress("2")), + Validator: types.StringToAddress("1"), + Authorize: true, + }, + }, + }, + } + + blockchain = &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: latestNumber} + }, + } + + secretManager = &mockSecretManager{ + HasSecretFunc: func(name string) bool { + assert.Equal(t, secrets.ValidatorKey, name) + + return true + }, + GetSecretFunc: func(name string) ([]byte, error) { + assert.Equal(t, secrets.ValidatorKey, name) + + return ecdsaKeyBytes, nil + }, + } + ) + + dirPath := createTestTempDirectory(t) + + assert.NoError( + t, + writeDataStore(path.Join(dirPath, snapshotMetadataFilename), metadata), + ) + + assert.NoError( + t, + writeDataStore(path.Join(dirPath, snapshotSnapshotsFilename), snapshots), + ) + + fm, err := NewForkManager( + logger, + blockchain, + nil, + secretManager, + dirPath, + epochSize, + map[string]interface{}{ + "type": "PoA", + "validator_type": "ecdsa", + }, + ) + + assert.NoError(t, err) + assert.NoError(t, fm.Initialize()) + + assert.NotNil(t, fm.keyManagers[validators.ECDSAValidatorType]) + assert.NotNil(t, fm.validatorStores[store.Snapshot]) + assert.NotNil(t, fm.hooksRegisters[PoA]) + }) + + t.Run("PoS and BLS", func(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + + secretManager = &mockSecretManager{ + HasSecretFunc: func(name string) bool { + assert.True(t, name == secrets.ValidatorKey || name == secrets.ValidatorBLSKey) + + return true + }, + GetSecretFunc: func(name string) ([]byte, error) { + assert.True(t, name == secrets.ValidatorKey || name == secrets.ValidatorBLSKey) + + if name == secrets.ValidatorKey { + return ecdsaKeyBytes, nil + } else { + return blsKeyBytes, nil + } + }, + } + ) + + fm, err := NewForkManager( + logger, + nil, + nil, + secretManager, + "", + epochSize, + map[string]interface{}{ + "type": "PoS", + "validator_type": "bls", + }, + ) + + assert.NoError(t, err) + assert.NoError(t, fm.Initialize()) + + assert.NotNil(t, fm.keyManagers[validators.BLSValidatorType]) + assert.NotNil(t, fm.validatorStores[store.Contract]) + assert.NotNil(t, fm.hooksRegisters[PoS]) + }) +} + +func TestForkManagerClose(t *testing.T) { + t.Parallel() + + t.Run("should call all Close methods of ValidatorStore", func(t *testing.T) { + t.Parallel() + + numCalls := 0 + + fm := &ForkManager{ + validatorStores: map[store.SourceType]ValidatorStore{ + store.Contract: &mockValidatorStore{ + CloseFunc: func() error { + numCalls++ + + return nil + }, + }, + store.Snapshot: &mockValidatorStore{ + CloseFunc: func() error { + numCalls++ + + return nil + }, + }, + }, + } + + assert.NoError(t, fm.Close()) + assert.Equal(t, 2, numCalls) + }) + + t.Run("should return error if one of Close method returns error", func(t *testing.T) { + t.Parallel() + + numCalls := 0 + + fm := &ForkManager{ + validatorStores: map[store.SourceType]ValidatorStore{ + // should call the either + store.Contract: &mockValidatorStore{ + CloseFunc: func() error { + numCalls++ + + return errTest + }, + }, + store.Snapshot: &mockValidatorStore{ + CloseFunc: func() error { + numCalls++ + + return errTest + }, + }, + }, + } + + assert.Equal(t, errTest, fm.Close()) + assert.Equal(t, 1, numCalls) + }) +} + +type MockKeyManager struct { + signer.KeyManager + ValType validators.ValidatorType +} + +func TestForkManagerGetSigner(t *testing.T) { + t.Parallel() + + var ( + ecdsaKeyManager = &MockKeyManager{ + ValType: validators.ECDSAValidatorType, + } + blsKeyManager = &MockKeyManager{ + ValType: validators.BLSValidatorType, + } + ) + + tests := []struct { + name string + forks IBFTForks + keyManagers map[validators.ValidatorType]signer.KeyManager + height uint64 + expectedSigner signer.Signer + expectedErr error + }{ + { + name: "should return ErrForkNotFound if fork not found", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + ValidatorType: validators.BLSValidatorType, + From: common.JSONNumber{Value: 11}, + To: &common.JSONNumber{Value: 20}, + }, + }, + keyManagers: map[validators.ValidatorType]signer.KeyManager{}, + height: 22, + expectedSigner: nil, + expectedErr: ErrForkNotFound, + }, + { + name: "should return ErrKeyManagerNotFound if fork managers is nil", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + }, + }, + keyManagers: map[validators.ValidatorType]signer.KeyManager{}, + height: 10, + expectedSigner: nil, + expectedErr: ErrKeyManagerNotFound, + }, + { + name: "should return err if fork not found for parent key manager", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 2}, + }, + }, + keyManagers: map[validators.ValidatorType]signer.KeyManager{ + validators.ECDSAValidatorType: MockKeyManager{}, + }, + height: 2, + expectedSigner: nil, + expectedErr: ErrForkNotFound, + }, + { + name: "should return the signer with single key manager if the height is 1", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + ValidatorType: validators.BLSValidatorType, + From: common.JSONNumber{Value: 11}, + }, + }, + keyManagers: map[validators.ValidatorType]signer.KeyManager{ + validators.ECDSAValidatorType: ecdsaKeyManager, + validators.BLSValidatorType: blsKeyManager, + }, + height: 1, + expectedSigner: signer.NewSigner(ecdsaKeyManager, nil), + }, + { + name: "should return the signer with different key manager and parent key manager", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + ValidatorType: validators.BLSValidatorType, + From: common.JSONNumber{Value: 11}, + }, + }, + keyManagers: map[validators.ValidatorType]signer.KeyManager{ + validators.ECDSAValidatorType: ecdsaKeyManager, + validators.BLSValidatorType: blsKeyManager, + }, + height: 11, + expectedSigner: signer.NewSigner(blsKeyManager, ecdsaKeyManager), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + fm := &ForkManager{ + forks: test.forks, + keyManagers: test.keyManagers, + } + + signer, err := fm.GetSigner(test.height) + + assert.Equal( + t, + test.expectedSigner, + signer, + ) + + assert.Equal( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestForkManagerGetValidatorStore(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + forks IBFTForks + validatorStores map[store.SourceType]ValidatorStore + height uint64 + expectedStore ValidatorStore + expectedErr error + }{ + { + name: "should return ErrForkNotFound if fork not found", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + ValidatorType: validators.BLSValidatorType, + From: common.JSONNumber{Value: 11}, + To: &common.JSONNumber{Value: 20}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{}, + height: 25, + expectedStore: nil, + expectedErr: ErrForkNotFound, + }, + { + name: "should return ErrValidatorStoreNotFound if validator store not found", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{}, + height: 25, + expectedStore: nil, + expectedErr: ErrValidatorStoreNotFound, + }, + { + name: "should return Snapshot store for PoA", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{ + store.Snapshot: &mockValidatorStore{}, + }, + height: 25, + expectedStore: &mockValidatorStore{}, + expectedErr: nil, + }, + { + name: "should return Contract store for PoS", + forks: IBFTForks{ + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{ + store.Contract: &mockValidatorStore{}, + }, + height: 25, + expectedStore: &mockValidatorStore{}, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + fm := &ForkManager{ + forks: test.forks, + validatorStores: test.validatorStores, + } + + store, err := fm.GetValidatorStore(test.height) + + assert.Equal( + t, + test.expectedStore, + store, + ) + + assert.Equal( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestForkManagerGetValidators(t *testing.T) { + t.Parallel() + + var epochSize uint64 = 10 + + tests := []struct { + name string + forks IBFTForks + validatorStores map[store.SourceType]ValidatorStore + height uint64 + expectedValidators validators.Validators + expectedErr error + }{ + { + name: "should return ErrForkNotFound if fork not found", + forks: IBFTForks{ + { + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 10}, + }, + { + ValidatorType: validators.BLSValidatorType, + From: common.JSONNumber{Value: 11}, + To: &common.JSONNumber{Value: 20}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{}, + height: 25, + expectedValidators: nil, + expectedErr: ErrForkNotFound, + }, + { + name: "should return ErrValidatorStoreNotFound if validator store not found", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{}, + height: 25, + expectedValidators: nil, + expectedErr: ErrValidatorStoreNotFound, + }, + { + name: "should return Validators", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 10}, + }, + }, + validatorStores: map[store.SourceType]ValidatorStore{ + store.Snapshot: &mockValidatorStore{ + GetValidatorsFunc: func(u1, u2, u3 uint64) (validators.Validators, error) { + assert.Equal(t, uint64(25), u1) // height + assert.Equal(t, epochSize, u2) // epochSize + assert.Equal(t, uint64(10), u3) // from + + return validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + validators.NewECDSAValidator(types.StringToAddress("2")), + ), nil + }, + }, + }, + height: 25, + expectedValidators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + validators.NewECDSAValidator(types.StringToAddress("2")), + ), + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + fm := &ForkManager{ + forks: test.forks, + validatorStores: test.validatorStores, + epochSize: epochSize, + } + + validators, err := fm.GetValidators(test.height) + + assert.Equal( + t, + test.expectedValidators, + validators, + ) + + assert.Equal( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestForkManagerGetHooks(t *testing.T) { + t.Parallel() + + var ( + height uint64 = 25 + + err1 = errors.New("error 1") + err2 = errors.New("error 2") + ) + + fm := &ForkManager{ + hooksRegisters: map[IBFTType]HooksRegister{ + PoA: &mockHooksRegister{ + RegisterHooksFunc: func(hooks *hook.Hooks, h uint64) { + assert.Equal(t, height, h) + + hooks.ModifyHeaderFunc = func(h *types.Header, a types.Address) error { + return err1 + } + }, + }, + PoS: &mockHooksRegister{ + RegisterHooksFunc: func(hooks *hook.Hooks, h uint64) { + assert.Equal(t, height, h) + + hooks.VerifyBlockFunc = func(b *types.Block) error { + return err2 + } + }, + }, + }, + } + + hooks := fm.GetHooks(height) + + assert.Equal(t, err1, hooks.ModifyHeader(&types.Header{}, types.StringToAddress("1"))) + assert.Equal(t, err2, hooks.VerifyBlock(&types.Block{}), nil) +} + +func TestForkManager_initializeKeyManagers(t *testing.T) { + t.Parallel() + + key, keyBytes, err := crypto.GenerateAndEncodeECDSAPrivateKey() + assert.NoError(t, err) + + tests := []struct { + name string + forks IBFTForks + secretManager *mockSecretManager + expectedErr error + expectedKeyManagers map[validators.ValidatorType]signer.KeyManager + }{ + { + name: "should return error if NewKeyManagerFromType fails", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ValidatorType("fake"), + From: common.JSONNumber{Value: 0}, + }, + }, + secretManager: nil, + expectedErr: errors.New("unsupported validator type: fake"), + expectedKeyManagers: map[validators.ValidatorType]signer.KeyManager{}, + }, + { + name: "should initializes key manager", + forks: IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 49}, + }, + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 50}, + }, + }, + secretManager: &mockSecretManager{ + HasSecretFunc: func(name string) bool { + assert.Equal(t, secrets.ValidatorKey, name) + + return true + }, + GetSecretFunc: func(name string) ([]byte, error) { + assert.Equal(t, secrets.ValidatorKey, name) + + return keyBytes, nil + }, + }, + expectedErr: nil, + expectedKeyManagers: map[validators.ValidatorType]signer.KeyManager{ + validators.ECDSAValidatorType: signer.NewECDSAKeyManagerFromKey(key), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + fm := &ForkManager{ + forks: test.forks, + secretsManager: test.secretManager, + keyManagers: map[validators.ValidatorType]signer.KeyManager{}, + } + + testHelper.AssertErrorMessageContains( + t, + fm.initializeKeyManagers(), + test.expectedErr, + ) + + assert.Equal( + t, + test.expectedKeyManagers, + fm.keyManagers, + ) + }) + } +} + +func TestForkManager_initializeValidatorStores(t *testing.T) { + t.Parallel() + + var ( + logger = hclog.NewNullLogger() + blockchain = &store.MockBlockchain{} + executor = &MockExecutor{} + + forks = IBFTForks{ + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 49}, + }, + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 50}, + }, + } + ) + + fm := &ForkManager{ + forks: forks, + validatorStores: map[store.SourceType]ValidatorStore{}, + logger: logger, + blockchain: blockchain, + executor: executor, + } + + assert.NoError(t, fm.initializeValidatorStores()) + + assert.NotNil( + t, + fm.validatorStores[store.Contract], + ) + + assert.Nil( + t, + fm.validatorStores[store.Snapshot], + ) +} + +func TestForkManager_initializeHooksRegisters(t *testing.T) { + t.Parallel() + + var ( + forks = IBFTForks{ + { + Type: PoA, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 0}, + To: &common.JSONNumber{Value: 49}, + }, + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 50}, + To: &common.JSONNumber{Value: 100}, + }, + { + Type: PoS, + ValidatorType: validators.ECDSAValidatorType, + From: common.JSONNumber{Value: 101}, + }, + } + ) + + fm := &ForkManager{ + forks: forks, + hooksRegisters: map[IBFTType]HooksRegister{}, + } + + fm.initializeHooksRegisters() + + assert.NotNil( + t, + fm.hooksRegisters[PoA], + ) + + assert.NotNil( + t, + fm.hooksRegisters[PoS], + ) +} diff --git a/consensus/ibft/fork/storewrapper.go b/consensus/ibft/fork/storewrapper.go new file mode 100644 index 0000000000..3b6b951095 --- /dev/null +++ b/consensus/ibft/fork/storewrapper.go @@ -0,0 +1,168 @@ +package fork + +import ( + "path/filepath" + + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/0xPolygon/polygon-edge/validators/store/contract" + "github.com/0xPolygon/polygon-edge/validators/store/snapshot" + "github.com/hashicorp/go-hclog" +) + +// SnapshotValidatorStoreWrapper is a wrapper of store.SnapshotValidatorStore +// in order to add initialization and closer process with side effect +type SnapshotValidatorStoreWrapper struct { + *snapshot.SnapshotValidatorStore + dirPath string +} + +// Close saves SnapshotValidator data into local storage +func (w *SnapshotValidatorStoreWrapper) Close() error { + // save data + var ( + metadata = w.GetSnapshotMetadata() + snapshots = w.GetSnapshots() + ) + + if err := writeDataStore(filepath.Join(w.dirPath, snapshotMetadataFilename), metadata); err != nil { + return err + } + + if err := writeDataStore(filepath.Join(w.dirPath, snapshotSnapshotsFilename), snapshots); err != nil { + return err + } + + return nil +} + +// GetValidators returns validators at the specific height +func (w *SnapshotValidatorStoreWrapper) GetValidators(height, _, _ uint64) (validators.Validators, error) { + // the biggest height of blocks that have been processed before the given height + return w.GetValidatorsByHeight(height - 1) +} + +// NewSnapshotValidatorStoreWrapper loads data from local storage and creates *SnapshotValidatorStoreWrapper +func NewSnapshotValidatorStoreWrapper( + logger hclog.Logger, + blockchain store.HeaderGetter, + getSigner func(uint64) (signer.Signer, error), + dirPath string, + epochSize uint64, +) (*SnapshotValidatorStoreWrapper, error) { + snapshotMeta, err := loadSnapshotMetadata(filepath.Join(dirPath, snapshotMetadataFilename)) + if err != nil { + return nil, err + } + + snapshots, err := loadSnapshots(filepath.Join(dirPath, snapshotSnapshotsFilename)) + if err != nil { + return nil, err + } + + snapshotStore, err := snapshot.NewSnapshotValidatorStore( + logger, + blockchain, + func(height uint64) (snapshot.SignerInterface, error) { + rawSigner, err := getSigner(height) + if err != nil { + return nil, err + } + + return snapshot.SignerInterface(rawSigner), nil + }, + epochSize, + snapshotMeta, + snapshots, + ) + + if err != nil { + return nil, err + } + + return &SnapshotValidatorStoreWrapper{ + SnapshotValidatorStore: snapshotStore, + dirPath: dirPath, + }, nil +} + +// ContractValidatorStoreWrapper is a wrapper of *contract.ContractValidatorStore +// in order to add Close and GetValidators +type ContractValidatorStoreWrapper struct { + *contract.ContractValidatorStore + getSigner func(uint64) (signer.Signer, error) +} + +// NewContractValidatorStoreWrapper creates *ContractValidatorStoreWrapper +func NewContractValidatorStoreWrapper( + logger hclog.Logger, + blockchain store.HeaderGetter, + executor contract.Executor, + getSigner func(uint64) (signer.Signer, error), +) (*ContractValidatorStoreWrapper, error) { + contractStore, err := contract.NewContractValidatorStore( + logger, + blockchain, + executor, + contract.DefaultValidatorSetCacheSize, + ) + + if err != nil { + return nil, err + } + + return &ContractValidatorStoreWrapper{ + ContractValidatorStore: contractStore, + getSigner: getSigner, + }, nil +} + +// Close is closer process +func (w *ContractValidatorStoreWrapper) Close() error { + return nil +} + +// GetValidators gets and returns validators at the given height +func (w *ContractValidatorStoreWrapper) GetValidators( + height, epochSize, forkFrom uint64, +) (validators.Validators, error) { + signer, err := w.getSigner(height) + if err != nil { + return nil, err + } + + return w.GetValidatorsByHeight( + signer.Type(), + calculateContractStoreFetchingHeight( + height, + epochSize, + forkFrom, + ), + ) +} + +// calculateContractStoreFetchingHeight calculates the block height at which ContractStore fetches validators +// based on height, epoch, and fork beginning height +func calculateContractStoreFetchingHeight(height, epochSize, forkFrom uint64) uint64 { + // calculates the beginning of the epoch the given height is in + beginningEpoch := (height / epochSize) * epochSize + + // calculates the end of the previous epoch + // to determine the height to fetch validators + fetchingHeight := uint64(0) + if beginningEpoch > 0 { + fetchingHeight = beginningEpoch - 1 + } + + // use the calculated height if it's bigger than or equal to from + if fetchingHeight >= forkFrom { + return fetchingHeight + } + + if forkFrom > 0 { + return forkFrom - 1 + } + + return forkFrom +} diff --git a/consensus/ibft/fork/storewrapper_test.go b/consensus/ibft/fork/storewrapper_test.go new file mode 100644 index 0000000000..5ab7e04e8f --- /dev/null +++ b/consensus/ibft/fork/storewrapper_test.go @@ -0,0 +1,414 @@ +package fork + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path" + "testing" + + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/0xPolygon/polygon-edge/validators/store/snapshot" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" +) + +var ( + errTest = errors.New("test") +) + +func createTestMetadataJSON(height uint64) string { + return fmt.Sprintf(`{"LastBlock": %d}`, height) +} + +func createTestSnapshotJSON(t *testing.T, snapshot *snapshot.Snapshot) string { + t.Helper() + + res, err := json.Marshal(snapshot) + assert.NoError(t, err) + + return string(res) +} + +func TestSnapshotValidatorStoreWrapper(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + storedSnapshotMetadata string + storedSnapshots string + blockchain store.HeaderGetter + signer signer.Signer + epochSize uint64 + err error + }{ + { + name: "should return error if loading metadata fails", + storedSnapshotMetadata: `hoge`, + storedSnapshots: "", + blockchain: nil, + signer: nil, + epochSize: 0, + err: &json.SyntaxError{}, + }, + { + name: "should return error if loading snapshots fails", + storedSnapshotMetadata: createTestMetadataJSON(10), + storedSnapshots: `fuga`, + blockchain: nil, + signer: nil, + epochSize: 0, + err: &json.SyntaxError{}, + }, + { + name: "should return error if initialize fails", + storedSnapshotMetadata: createTestMetadataJSON(0), + storedSnapshots: "[]", + blockchain: &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: 0} + }, + }, + signer: nil, + epochSize: 10, + err: fmt.Errorf("signer not found %d", 0), + }, + { + name: "should succeed", + storedSnapshotMetadata: createTestMetadataJSON(10), + storedSnapshots: fmt.Sprintf("[%s]", createTestSnapshotJSON( + t, + &snapshot.Snapshot{ + Number: 10, + Hash: types.BytesToHash([]byte{0x10}).String(), + Set: validators.NewECDSAValidatorSet(), + Votes: []*store.Vote{}, + }, + )), + blockchain: &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: 10} + }, + }, + signer: nil, + epochSize: 10, + err: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + dirPath := createTestTempDirectory(t) + + assert.NoError( + t, + os.WriteFile(path.Join(dirPath, snapshotMetadataFilename), []byte(test.storedSnapshotMetadata), 0600), + ) + + assert.NoError( + t, + os.WriteFile(path.Join(dirPath, snapshotSnapshotsFilename), []byte(test.storedSnapshots), 0600), + ) + + store, err := NewSnapshotValidatorStoreWrapper( + hclog.NewNullLogger(), + test.blockchain, + func(u uint64) (signer.Signer, error) { + return test.signer, nil + }, + dirPath, + test.epochSize, + ) + + testHelper.AssertErrorMessageContains( + t, + test.err, + err, + ) + + if store != nil { + assert.Equal( + t, + dirPath, + store.dirPath, + ) + } + }) + } +} + +func TestSnapshotValidatorStoreWrapperGetValidators(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + metadata = &snapshot.SnapshotMetadata{ + LastBlock: 10, + } + snapshots = []*snapshot.Snapshot{ + { + Number: 10, + Hash: types.StringToHash("1").String(), + Set: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + ), + Votes: []*store.Vote{}, + }, + } + ) + + store, err := snapshot.NewSnapshotValidatorStore( + hclog.NewNullLogger(), + &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: 10} + }, + }, + func(u uint64) (snapshot.SignerInterface, error) { + return nil, nil + }, + epochSize, + metadata, + snapshots, + ) + + assert.NoError(t, err) + + wrapper := SnapshotValidatorStoreWrapper{ + SnapshotValidatorStore: store, + } + + vals, err := wrapper.GetValidators(11, 0, 0) + assert.NoError(t, err) + assert.Equal(t, snapshots[0].Set, vals) +} + +func TestSnapshotValidatorStoreWrapperClose(t *testing.T) { + t.Parallel() + + var ( + dirPath = createTestTempDirectory(t) + + epochSize uint64 = 10 + metadata = &snapshot.SnapshotMetadata{ + LastBlock: 10, + } + snapshots = []*snapshot.Snapshot{ + { + Number: 10, + Hash: types.StringToHash("1").String(), + Set: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(types.StringToAddress("1")), + ), + Votes: []*store.Vote{}, + }, + } + ) + + store, err := snapshot.NewSnapshotValidatorStore( + hclog.NewNullLogger(), + &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return &types.Header{Number: 10} + }, + }, + func(u uint64) (snapshot.SignerInterface, error) { + return nil, nil + }, + epochSize, + metadata, + snapshots, + ) + + assert.NoError(t, err) + + wrapper := SnapshotValidatorStoreWrapper{ + dirPath: dirPath, + SnapshotValidatorStore: store, + } + + assert.NoError(t, wrapper.Close()) + + savedMetadataFile, err := os.ReadFile(path.Join(dirPath, snapshotMetadataFilename)) + assert.NoError(t, err) + assert.JSONEq( + t, + createTestMetadataJSON(metadata.LastBlock), + string(savedMetadataFile), + ) + + savedSnapshots, err := os.ReadFile(path.Join(dirPath, snapshotSnapshotsFilename)) + assert.NoError(t, err) + assert.JSONEq( + t, + fmt.Sprintf("[%s]", createTestSnapshotJSON(t, snapshots[0])), + string(savedSnapshots), + ) +} + +type MockExecutor struct { + BeginTxnFunc func(types.Hash, *types.Header, types.Address) (*state.Transition, error) +} + +func (m *MockExecutor) BeginTxn(hash types.Hash, header *types.Header, addr types.Address) (*state.Transition, error) { + return m.BeginTxnFunc(hash, header, addr) +} + +func TestNewContractValidatorStoreWrapper(t *testing.T) { + t.Parallel() + + _, err := NewContractValidatorStoreWrapper( + hclog.NewNullLogger(), + &store.MockBlockchain{}, + &MockExecutor{}, + func(u uint64) (signer.Signer, error) { + return nil, nil + }, + ) + + assert.NoError(t, err) +} + +func TestNewContractValidatorStoreWrapperClose(t *testing.T) { + t.Parallel() + + wrapper, err := NewContractValidatorStoreWrapper( + hclog.NewNullLogger(), + &store.MockBlockchain{}, + &MockExecutor{}, + func(u uint64) (signer.Signer, error) { + return nil, nil + }, + ) + + assert.NoError(t, err) + assert.NoError(t, wrapper.Close()) +} + +func TestNewContractValidatorStoreWrapperGetValidators(t *testing.T) { + t.Parallel() + + t.Run("should return error if getSigner returns error", func(t *testing.T) { + t.Parallel() + + wrapper, err := NewContractValidatorStoreWrapper( + hclog.NewNullLogger(), + &store.MockBlockchain{}, + &MockExecutor{}, + func(u uint64) (signer.Signer, error) { + return nil, errTest + }, + ) + + assert.NoError(t, err) + + res, err := wrapper.GetValidators(0, 0, 0) + assert.Nil(t, res) + assert.ErrorIs(t, errTest, err) + }) + + t.Run("should return error if GetValidatorsByHeight returns error", func(t *testing.T) { + t.Parallel() + + wrapper, err := NewContractValidatorStoreWrapper( + hclog.NewNullLogger(), + &store.MockBlockchain{ + GetHeaderByNumberFn: func(u uint64) (*types.Header, bool) { + return nil, false + }, + }, + &MockExecutor{}, + func(u uint64) (signer.Signer, error) { + return signer.NewSigner( + &signer.ECDSAKeyManager{}, + nil, + ), nil + }, + ) + + assert.NoError(t, err) + + res, err := wrapper.GetValidators(10, 10, 0) + assert.Nil(t, res) + assert.ErrorContains(t, err, "header not found at 9") + }) +} + +func Test_calculateContractStoreFetchingHeight(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + height uint64 + epochSize uint64 + forkFrom uint64 + expected uint64 + }{ + { + name: "should return 0 if the height is 2 (in the first epoch)", + height: 2, + epochSize: 10, + forkFrom: 0, + expected: 0, + }, + { + name: "should return 0 if the height is 9 (in the first epoch)", + height: 9, + epochSize: 10, + forkFrom: 0, + expected: 0, + }, + { + name: "should return 9 if the height is 10 (in the second epoch)", + height: 10, + epochSize: 10, + forkFrom: 0, + expected: 9, + }, + { + name: "should return 9 if the height is 19 (in the second epoch)", + height: 19, + epochSize: 10, + forkFrom: 0, + expected: 9, + }, + { + name: "should return 49 if the height is 10 but forkFrom is 50", + height: 10, + epochSize: 10, + forkFrom: 50, + expected: 49, + }, + { + name: "should return 59 if the height is 60 and forkFrom is 50", + height: 60, + epochSize: 10, + forkFrom: 50, + expected: 59, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + calculateContractStoreFetchingHeight(test.height, test.epochSize, test.forkFrom), + ) + }) + } +} diff --git a/consensus/ibft/fork/type.go b/consensus/ibft/fork/type.go new file mode 100644 index 0000000000..9c66362259 --- /dev/null +++ b/consensus/ibft/fork/type.go @@ -0,0 +1,51 @@ +package fork + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/validators/store" +) + +// Define the type of the IBFT consensus +type IBFTType string + +const ( + // PoA defines the Proof of Authority IBFT type, + // where the validator set is changed through voting / pre-set in genesis + PoA IBFTType = "PoA" + + // PoS defines the Proof of Stake IBFT type, + // where the validator set it changed through staking on the Staking Smart Contract + PoS IBFTType = "PoS" +) + +// ibftTypes is the map used for easy string -> IBFTType lookups +var ibftTypes = map[string]IBFTType{ + "PoA": PoA, + "PoS": PoS, +} + +// ibftTypesToSourceType defines validator set type used under each IBFT Type +// Right now each IBFT Type is correspond one-to-one with ValidatorStore +// In other words, PoA always uses SnapshotValidatorStore while PoS uses ContractValidatorStore +// By definition, PoA can fetch validators from ContractValidatorStore +var ibftTypesToSourceType = map[IBFTType]store.SourceType{ + PoA: store.Snapshot, + PoS: store.Contract, +} + +// String is a helper method for casting a IBFTType to a string representation +func (t IBFTType) String() string { + return string(t) +} + +// ParseIBFTType converts a ibftType string representation to a IBFTType +func ParseIBFTType(ibftType string) (IBFTType, error) { + // Check if the cast is possible + castType, ok := ibftTypes[ibftType] + if !ok { + return castType, fmt.Errorf("invalid IBFT type %s", ibftType) + } + + return castType, nil +} diff --git a/consensus/ibft/fork/type_test.go b/consensus/ibft/fork/type_test.go new file mode 100644 index 0000000000..e617749623 --- /dev/null +++ b/consensus/ibft/fork/type_test.go @@ -0,0 +1,74 @@ +package fork + +import ( + "errors" + "testing" + + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/stretchr/testify/assert" +) + +func TestIBFTTypeString(t *testing.T) { + t.Parallel() + + cases := map[IBFTType]string{ + PoA: "PoA", + PoS: "PoS", + } + + for typ, expected := range cases { + assert.Equal( + t, + expected, + typ.String(), + ) + } +} + +func TestParseIBFTType(t *testing.T) { + t.Parallel() + + tests := []struct { + value string + res IBFTType + err error + }{ + { + value: "PoA", + res: PoA, + err: nil, + }, + { + value: "PoS", + res: PoS, + err: nil, + }, + { + value: "hoge", + res: IBFTType(""), + err: errors.New("invalid IBFT type hoge"), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.value, func(t *testing.T) { + t.Parallel() + + res, err := ParseIBFTType(test.value) + + assert.Equal( + t, + test.res, + res, + ) + + testHelper.AssertErrorMessageContains( + t, + test.err, + err, + ) + }) + } +} diff --git a/consensus/ibft/header_hash.go b/consensus/ibft/header_hash.go deleted file mode 100644 index 99e3d82516..0000000000 --- a/consensus/ibft/header_hash.go +++ /dev/null @@ -1,45 +0,0 @@ -package ibft - -import ( - "github.com/0xPolygon/polygon-edge/helper/keccak" - "github.com/0xPolygon/polygon-edge/types" - "github.com/umbracle/fastrlp" -) - -// istanbulHeaderHash defines the custom implementation for getting the header hash, -// because of the extraData field -func istanbulHeaderHash(h *types.Header) types.Hash { - // this function replaces extra so we need to make a copy - h = h.Copy() // Remove later - - arena := fastrlp.DefaultArenaPool.Get() - defer fastrlp.DefaultArenaPool.Put(arena) - - // when hashing the block for signing we have to remove from - // the extra field the seal and committed seal items - extra, err := getIbftExtra(h) - if err != nil { - return types.Hash{} - } - - putIbftExtraValidators(h, extra.Validators) - - vv := arena.NewArray() - vv.Set(arena.NewBytes(h.ParentHash.Bytes())) - vv.Set(arena.NewBytes(h.Sha3Uncles.Bytes())) - vv.Set(arena.NewBytes(h.Miner.Bytes())) - vv.Set(arena.NewBytes(h.StateRoot.Bytes())) - vv.Set(arena.NewBytes(h.TxRoot.Bytes())) - vv.Set(arena.NewBytes(h.ReceiptsRoot.Bytes())) - vv.Set(arena.NewBytes(h.LogsBloom[:])) - vv.Set(arena.NewUint(h.Difficulty)) - vv.Set(arena.NewUint(h.Number)) - vv.Set(arena.NewUint(h.GasLimit)) - vv.Set(arena.NewUint(h.GasUsed)) - vv.Set(arena.NewUint(h.Timestamp)) - vv.Set(arena.NewCopyBytes(h.ExtraData)) - - buf := keccak.Keccak256Rlp(nil, vv) - - return types.BytesToHash(buf) -} diff --git a/consensus/ibft/helper_test.go b/consensus/ibft/helper_test.go new file mode 100644 index 0000000000..0f12b70789 --- /dev/null +++ b/consensus/ibft/helper_test.go @@ -0,0 +1,92 @@ +package ibft + +import ( + "crypto/ecdsa" + "strconv" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +type testerAccount struct { + alias string + priv *ecdsa.PrivateKey +} + +func (t *testerAccount) Address() types.Address { + return crypto.PubKeyToAddress(&t.priv.PublicKey) +} + +type testerAccountPool struct { + t *testing.T + accounts []*testerAccount +} + +func newTesterAccountPool(t *testing.T, num ...int) *testerAccountPool { + t.Helper() + + pool := &testerAccountPool{ + t: t, + accounts: []*testerAccount{}, + } + + if len(num) == 1 { + for i := 0; i < num[0]; i++ { + key, _ := crypto.GenerateECDSAKey() + + pool.accounts = append(pool.accounts, &testerAccount{ + alias: strconv.Itoa(i), + priv: key, + }) + } + } + + return pool +} + +func (ap *testerAccountPool) add(accounts ...string) { + ap.t.Helper() + + for _, account := range accounts { + if acct := ap.get(account); acct != nil { + continue + } + + priv, err := crypto.GenerateECDSAKey() + if err != nil { + panic("BUG: Failed to generate crypto key") + } + + ap.accounts = append(ap.accounts, &testerAccount{ + alias: account, + priv: priv, + }) + } +} + +func (ap *testerAccountPool) get(name string) *testerAccount { + ap.t.Helper() + + for _, i := range ap.accounts { + if i.alias == name { + return i + } + } + + return nil +} + +func (ap *testerAccountPool) ValidatorSet() validators.Validators { + ap.t.Helper() + + v := validators.NewECDSAValidatorSet() + for _, i := range ap.accounts { + _ = v.Add(&validators.ECDSAValidator{ + Address: i.Address(), + }) + } + + return v +} diff --git a/consensus/ibft/hook/hook.go b/consensus/ibft/hook/hook.go new file mode 100644 index 0000000000..ca4b2c3af7 --- /dev/null +++ b/consensus/ibft/hook/hook.go @@ -0,0 +1,86 @@ +package hook + +import ( + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" +) + +type ShouldWriteTransactionsFunc func(uint64) bool + +type ModifyHeaderFunc func(*types.Header, types.Address) error + +type VerifyHeaderFunc func(*types.Header) error + +type VerifyBlockFunc func(*types.Block) error + +type ProcessHeaderFunc func(*types.Header) error + +type PreCommitStateFunc func(*types.Header, *state.Transition) error + +type PostInsertBlockFunc func(*types.Block) error + +type Hooks struct { + ShouldWriteTransactionFunc ShouldWriteTransactionsFunc + ModifyHeaderFunc ModifyHeaderFunc + VerifyHeaderFunc VerifyHeaderFunc + VerifyBlockFunc VerifyBlockFunc + ProcessHeaderFunc ProcessHeaderFunc + PreCommitStateFunc PreCommitStateFunc + PostInsertBlockFunc PostInsertBlockFunc +} + +func (m *Hooks) ShouldWriteTransactions(height uint64) bool { + if m.ShouldWriteTransactionFunc != nil { + return m.ShouldWriteTransactionFunc(height) + } + + return true +} + +func (m *Hooks) ModifyHeader(header *types.Header, proposer types.Address) error { + if m.ModifyHeaderFunc != nil { + return m.ModifyHeaderFunc(header, proposer) + } + + return nil +} + +func (m *Hooks) VerifyHeader(header *types.Header) error { + if m.VerifyHeaderFunc != nil { + return m.VerifyHeaderFunc(header) + } + + return nil +} + +func (m *Hooks) VerifyBlock(block *types.Block) error { + if m.VerifyBlockFunc != nil { + return m.VerifyBlockFunc(block) + } + + return nil +} + +func (m *Hooks) ProcessHeader(header *types.Header) error { + if m.ProcessHeaderFunc != nil { + return m.ProcessHeaderFunc(header) + } + + return nil +} + +func (m *Hooks) PreCommitState(header *types.Header, txn *state.Transition) error { + if m.PreCommitStateFunc != nil { + return m.PreCommitStateFunc(header, txn) + } + + return nil +} + +func (m *Hooks) PostInsertBlock(block *types.Block) error { + if m.PostInsertBlockFunc != nil { + return m.PostInsertBlockFunc(block) + } + + return nil +} diff --git a/consensus/ibft/hook/hook_test.go b/consensus/ibft/hook/hook_test.go new file mode 100644 index 0000000000..5d06a8d205 --- /dev/null +++ b/consensus/ibft/hook/hook_test.go @@ -0,0 +1,343 @@ +package hook + +import ( + "errors" + "testing" + + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +var ( + testHeader = &types.Header{ + Number: 1, + Miner: []byte{}, + ExtraData: []byte{}, + } + + testBlock = &types.Block{ + Header: testHeader, + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + + addr1 = types.StringToAddress("1") + + errTest = errors.New("error test") +) + +func newTestHooks( + shouldWriteTransactions ShouldWriteTransactionsFunc, + modifyHeader ModifyHeaderFunc, + verifyHeader VerifyHeaderFunc, + verifyBlock VerifyBlockFunc, + processHeaderFunc ProcessHeaderFunc, + preCommitState PreCommitStateFunc, + postInsertBlock PostInsertBlockFunc, +) *Hooks { + return &Hooks{ + ShouldWriteTransactionFunc: shouldWriteTransactions, + ModifyHeaderFunc: modifyHeader, + VerifyHeaderFunc: verifyHeader, + VerifyBlockFunc: verifyBlock, + ProcessHeaderFunc: processHeaderFunc, + PreCommitStateFunc: preCommitState, + PostInsertBlockFunc: postInsertBlock, + } +} + +func TestShouldWriteTransactions(t *testing.T) { + t.Parallel() + + t.Run("should return true if the function is not set", func(t *testing.T) { + t.Parallel() + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.True(t, hooks.ShouldWriteTransactions(0)) + }) + + t.Run("should call ShouldWriteTransactionFunc", func(t *testing.T) { + t.Parallel() + + shouldWriteTransaction := func(x uint64) bool { + assert.LessOrEqual(t, x, uint64(1)) + + return x != 0 + } + + hooks := newTestHooks(shouldWriteTransaction, nil, nil, nil, nil, nil, nil) + + assert.False(t, hooks.ShouldWriteTransactions(0)) + assert.True(t, hooks.ShouldWriteTransactions(1)) + }) +} + +func TestModifyHeader(t *testing.T) { + t.Parallel() + + t.Run("should do nothing if the function is not set", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.ModifyHeader(header, addr1)) + assert.Equal(t, testHeader, header) + }) + + t.Run("should call ModifyHeader", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + modifyHeader := func(h *types.Header, proposer types.Address) error { + assert.Equal(t, header, h) + assert.Equal(t, addr1, proposer) + + h.Miner = proposer.Bytes() + + return nil + } + + hooks := newTestHooks(nil, modifyHeader, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.ModifyHeader(header, addr1)) + assert.Equal( + t, + &types.Header{ + Number: 1, + Miner: addr1.Bytes(), + ExtraData: []byte{}, + }, + header, + ) + }) +} + +//nolint:dupl +func TestVerifyHeader(t *testing.T) { + t.Parallel() + + t.Run("should return nil if the function is not set", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.VerifyHeader(header)) + assert.Equal(t, testHeader, header) + }) + + t.Run("should call VerifyHeader", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + verifyHeader := func(h *types.Header) error { + assert.Equal(t, header, h) + + return errTest + } + + hooks := newTestHooks(nil, nil, verifyHeader, nil, nil, nil, nil) + + assert.Equal( + t, + errTest, + hooks.VerifyHeader(header), + ) + assert.Equal( + t, + testHeader, + header, + ) + }) +} + +//nolint:dupl +func TestVerifyBlock(t *testing.T) { + t.Parallel() + + t.Run("should return nil if the function is not set", func(t *testing.T) { + t.Parallel() + + block := &types.Block{ + Header: testBlock.Header.Copy(), + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.VerifyBlock(testBlock)) + assert.Equal(t, testBlock, block) + }) + + t.Run("should call VerifyHeader", func(t *testing.T) { + t.Parallel() + + block := &types.Block{ + Header: testBlock.Header.Copy(), + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + + verifyBlock := func(b *types.Block) error { + assert.Equal(t, block, b) + + return errTest + } + + hooks := newTestHooks(nil, nil, nil, verifyBlock, nil, nil, nil) + + assert.Equal( + t, + errTest, + hooks.VerifyBlock(block), + ) + assert.Equal( + t, + testBlock, + block, + ) + }) +} + +//nolint:dupl +func TestProcessHeader(t *testing.T) { + t.Parallel() + + t.Run("should do nothing if the function is not set", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.ProcessHeader(header)) + assert.Equal(t, testHeader, header) + }) + + t.Run("should call ProcessHeader", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + processHeader := func(h *types.Header) error { + assert.Equal(t, header, h) + + return errTest + } + + hooks := newTestHooks(nil, nil, nil, nil, processHeader, nil, nil) + + assert.Equal( + t, + errTest, + hooks.ProcessHeader(header), + ) + assert.Equal( + t, + testHeader, + header, + ) + }) +} + +func TestPreCommitState(t *testing.T) { + t.Parallel() + + var ( + txn = &state.Transition{} + ) + + t.Run("should do nothing if the function is not set", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.PreCommitState(header, txn)) + assert.Equal(t, testHeader, header) + }) + + t.Run("should call ProcessHeader", func(t *testing.T) { + t.Parallel() + + header := testHeader.Copy() + + preCommitState := func(h *types.Header, x *state.Transition) error { + assert.Equal(t, header, h) + assert.Equal(t, txn, x) + + return errTest + } + + hooks := newTestHooks(nil, nil, nil, nil, nil, preCommitState, nil) + + assert.Equal( + t, + errTest, + hooks.PreCommitState(header, txn), + ) + assert.Equal( + t, + testHeader, + header, + ) + }) +} + +//nolint:dupl +func TestPostInsertBlock(t *testing.T) { + t.Parallel() + + t.Run("should do nothing if the function is not set", func(t *testing.T) { + t.Parallel() + + block := &types.Block{ + Header: testBlock.Header.Copy(), + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, nil) + + assert.Nil(t, hooks.PostInsertBlock(block)) + assert.Equal(t, testBlock, block) + }) + + t.Run("should call ProcessHeader", func(t *testing.T) { + t.Parallel() + + block := &types.Block{ + Header: testBlock.Header.Copy(), + Transactions: []*types.Transaction{}, + Uncles: []*types.Header{}, + } + + postBlock := func(b *types.Block) error { + assert.Equal(t, block, b) + + return errTest + } + + hooks := newTestHooks(nil, nil, nil, nil, nil, nil, postBlock) + + assert.Equal( + t, + errTest, + hooks.PostInsertBlock(block), + ) + assert.Equal( + t, + testBlock, + block, + ) + }) +} diff --git a/consensus/ibft/hooks.go b/consensus/ibft/hooks.go deleted file mode 100644 index 8a69161a83..0000000000 --- a/consensus/ibft/hooks.go +++ /dev/null @@ -1,174 +0,0 @@ -package ibft - -import ( - "fmt" - - "github.com/0xPolygon/polygon-edge/helper/common" -) - -// Define the type of the IBFT consensus - -type MechanismType string - -const ( - // PoA defines the Proof of Authority IBFT type, - // where the validator set is changed through voting / pre-set in genesis - PoA MechanismType = "PoA" - - // PoS defines the Proof of Stake IBFT type, - // where the validator set it changed through staking on the Staking SC - PoS MechanismType = "PoS" -) - -// mechanismTypes is the map used for easy string -> mechanism MechanismType lookups -var mechanismTypes = map[string]MechanismType{ - "PoA": PoA, - "PoS": PoS, -} - -// String is a helper method for casting a MechanismType to a string representation -func (t MechanismType) String() string { - return string(t) -} - -// ParseType converts a mechanism string representation to a MechanismType -func ParseType(mechanism string) (MechanismType, error) { - // Check if the cast is possible - castType, ok := mechanismTypes[mechanism] - if !ok { - return castType, fmt.Errorf("invalid IBFT mechanism type %s", mechanism) - } - - return castType, nil -} - -// Define the type of Hook - -type HookType string - -const ( - // POA // - - // VerifyHeadersHook defines additional checks that need to happen - // when verifying the headers - VerifyHeadersHook HookType = "VerifyHeadersHook" - - // ProcessHeadersHook defines additional steps that need to happen - // when processing the headers - ProcessHeadersHook HookType = "ProcessHeadersHook" - - // InsertBlockHook defines additional steps that need to happen - // when inserting a block into the chain - InsertBlockHook HookType = "InsertBlockHook" - - // CandidateVoteHook defines additional steps that need to happen - // when building a block (candidate voting) - CandidateVoteHook HookType = "CandidateVoteHook" - - // POS // - - // VerifyBlockHook defines the additional verification steps for the PoS mechanism - VerifyBlockHook HookType = "VerifyBlockHook" - - // PreStateCommitHook defines the additional state transition injection - PreStateCommitHook HookType = "PreStateCommitHook" -) - -type ConsensusMechanism interface { - // GetType returns the type of IBFT consensus mechanism (PoA / PoS) - GetType() MechanismType - - // GetHookMap returns the hooks registered with the specific consensus mechanism - GetHookMap() map[HookType]func(interface{}) error - - // IsAvailable returns whether the corresponding hook is available - IsAvailable(hook HookType, height uint64) bool - - // ShouldWriteTransactions returns whether transactions should be written to a block - // from the TxPool - ShouldWriteTransactions(blockNumber uint64) bool - - // initializeHookMap initializes the hook map - initializeHookMap() -} - -type BaseConsensusMechanism struct { - // Reference to the main IBFT implementation - ibft *backendIBFT - - // hookMap is the collection of registered hooks - hookMap map[HookType]func(interface{}) error - - // Used for easy lookups - mechanismType MechanismType - - // Available periods - From uint64 - To *uint64 -} - -// initializeParams initializes mechanism parameters from chain config -func (base *BaseConsensusMechanism) initializeParams(params *IBFTFork) error { - if params == nil { - return nil - } - - base.From = params.From.Value - - if params.To != nil { - if params.To.Value < base.From { - return fmt.Errorf( - `"to" must be grater than or equal to from: from=%d, to=%d`, - base.From, - params.To.Value, - ) - } - - base.To = ¶ms.To.Value - } - - return nil -} - -// GetType implements the ConsensusMechanism interface method -func (base *BaseConsensusMechanism) GetType() MechanismType { - return base.mechanismType -} - -// GetHookMap implements the ConsensusMechanism interface method -func (base *BaseConsensusMechanism) GetHookMap() map[HookType]func(interface{}) error { - return base.hookMap -} - -// IsInRange returns indicates if the given blockNumber is between from and to -func (base *BaseConsensusMechanism) IsInRange(blockNumber uint64) bool { - // not ready - if blockNumber < base.From { - return false - } - - // expired - if base.To != nil && *base.To < blockNumber { - return false - } - - return true -} - -// IBFT Fork represents setting in params.engine.ibft of genesis.json -type IBFTFork struct { - Type MechanismType `json:"type"` - Deployment *common.JSONNumber `json:"deployment,omitempty"` - From common.JSONNumber `json:"from"` - To *common.JSONNumber `json:"to,omitempty"` - MaxValidatorCount *common.JSONNumber `json:"maxValidatorCount,omitempty"` - MinValidatorCount *common.JSONNumber `json:"minValidatorCount,omitempty"` -} - -// ConsensusMechanismFactory is the factory function to create a consensus mechanism -type ConsensusMechanismFactory func(ibft *backendIBFT, params *IBFTFork) (ConsensusMechanism, error) - -var mechanismBackends = map[MechanismType]ConsensusMechanismFactory{ - PoA: PoAFactory, - PoS: PoSFactory, -} diff --git a/consensus/ibft/ibft.go b/consensus/ibft/ibft.go index 306ecdd323..15b6bc692b 100644 --- a/consensus/ibft/ibft.go +++ b/consensus/ibft/ibft.go @@ -1,24 +1,22 @@ package ibft import ( - "crypto/ecdsa" - "encoding/json" "errors" "fmt" "time" "github.com/0xPolygon/polygon-edge/blockchain" "github.com/0xPolygon/polygon-edge/consensus" - + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" - "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/common" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/helper/progress" "github.com/0xPolygon/polygon-edge/network" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/state" "github.com/0xPolygon/polygon-edge/syncer" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" "github.com/hashicorp/go-hclog" "google.golang.org/grpc" ) @@ -26,11 +24,18 @@ import ( const ( DefaultEpochSize = 100000 IbftKeyName = "validator.key" - ibftProto = "/ibft/0.2" + KeyEpochSize = "epochSize" + + ibftProto = "/ibft/0.2" ) var ( - ErrInvalidHookParam = errors.New("invalid IBFT hook param passed in") + ErrInvalidHookParam = errors.New("invalid IBFT hook param passed in") + ErrProposerSealByNonValidator = errors.New("proposer seal by non-validator") + ErrInvalidMixHash = errors.New("invalid mixhash") + ErrInvalidSha3Uncles = errors.New("invalid sha3 uncles") + ErrWrongDifficulty = errors.New("wrong difficulty") + ErrParentCommittedSealsNotFound = errors.New("parent committed seals not found") ) type txPoolInterface interface { @@ -43,42 +48,46 @@ type txPoolInterface interface { ResetWithHeaders(headers ...*types.Header) } +type forkManagerInterface interface { + Initialize() error + Close() error + GetSigner(uint64) (signer.Signer, error) + GetValidatorStore(uint64) (fork.ValidatorStore, error) + GetValidators(uint64) (validators.Validators, error) + GetHooks(uint64) fork.HooksInterface +} + // backendIBFT represents the IBFT consensus mechanism object type backendIBFT struct { - logger hclog.Logger - - config *consensus.Config // Consensus configuration - consensus *IBFTConsensus - blockchain *blockchain.Blockchain // Interface exposed by the blockchain layer - network *network.Server // Reference to the networking layer - executor *state.Executor // Reference to the state executor - txpool txPoolInterface // Reference to the transaction pool - syncer syncer.Syncer // Reference to the sync protocol - Grpc *grpc.Server // gRPC configuration - - metrics *consensus.Metrics - - secretsManager secrets.SecretsManager - - validatorKey *ecdsa.PrivateKey // Private key for the validator - validatorKeyAddr types.Address - activeValidatorSet ValidatorSet - - store *snapshotStore // Snapshot store that keeps track of all snapshots - transport transport // Reference to the transport protocol - operator *operator - - mechanisms []ConsensusMechanism // IBFT ConsensusMechanism used (PoA / PoS) - + // Static References + logger hclog.Logger // Reference to the logging + blockchain *blockchain.Blockchain // Reference to the blockchain layer + network *network.Server // Reference to the networking layer + executor *state.Executor // Reference to the state executor + txpool txPoolInterface // Reference to the transaction pool + syncer syncer.Syncer // Reference to the sync protocol + secretsManager secrets.SecretsManager // Reference to the secret manager + Grpc *grpc.Server // Reference to the gRPC manager + operator *operator // Reference to the gRPC service of IBFT + transport transport // Reference to the transport protocol + metrics *consensus.Metrics // Reference to the metrics service + + // Dynamic References + forkManager forkManagerInterface // Manager to hold IBFT Forks + currentSigner signer.Signer // Signer at current sequence + currentValidators validators.Validators // signer at current sequence + currentHooks fork.HooksInterface // Hooks at current sequence + + // Configurations + config *consensus.Config // Consensus configuration epochSize uint64 quorumSizeBlockNum uint64 + blockTime time.Duration // Minimum block generation time in seconds + sealing bool // Flag indicating if the node is a sealer - blockTime time.Duration // Minimum block generation time in seconds - - sealing bool // Flag indicating if the node is a sealer - + // Channels closeCh chan struct{} // Channel for closing } @@ -90,7 +99,7 @@ func Factory(params *consensus.Params) (consensus.Consensus, error) { quorumSizeBlockNum = uint64(0) ) - if definedEpochSize, ok := params.Config.Config["epochSize"]; ok { + if definedEpochSize, ok := params.Config.Config[KeyEpochSize]; ok { // Epoch size is defined, use the passed in one readSize, ok := definedEpochSize.(float64) if !ok { @@ -110,65 +119,57 @@ func Factory(params *consensus.Params) (consensus.Consensus, error) { quorumSizeBlockNum = uint64(readBlockNum) } + logger := params.Logger.Named("ibft") + + forkManager, err := fork.NewForkManager( + logger, + params.Blockchain, + params.Executor, + params.SecretsManager, + params.Config.Path, + epochSize, + params.Config.Config, + ) + + if err != nil { + return nil, err + } + p := &backendIBFT{ - logger: params.Logger.Named("ibft"), - config: params.Config, - Grpc: params.Grpc, - blockchain: params.Blockchain, - executor: params.Executor, - closeCh: make(chan struct{}), - txpool: params.TxPool, - network: params.Network, - epochSize: epochSize, - quorumSizeBlockNum: quorumSizeBlockNum, - sealing: params.Seal, - metrics: params.Metrics, - secretsManager: params.SecretsManager, - blockTime: time.Duration(params.BlockTime) * time.Second, + // References + logger: logger, + blockchain: params.Blockchain, + network: params.Network, + executor: params.Executor, + txpool: params.TxPool, syncer: syncer.NewSyncer( params.Logger, params.Network, params.Blockchain, - time.Duration(params.BlockTime)*3*time.Second), - } + time.Duration(params.BlockTime)*3*time.Second, + ), + secretsManager: params.SecretsManager, + Grpc: params.Grpc, + metrics: params.Metrics, + forkManager: forkManager, + + // Configurations + config: params.Config, + epochSize: epochSize, + quorumSizeBlockNum: quorumSizeBlockNum, + blockTime: time.Duration(params.BlockTime) * time.Second, + sealing: params.Seal, - // Initialize the mechanism - if err := p.setupMechanism(); err != nil { - return nil, err + // Channels + closeCh: make(chan struct{}), } // Istanbul requires a different header hash function - types.HeaderHash = istanbulHeaderHash + p.SetHeaderHash() return p, nil } -// runHook runs a specified hook if it is present in the hook map -func (i *backendIBFT) runHook(hookName HookType, height uint64, hookParam interface{}) error { - for _, mechanism := range i.mechanisms { - if !mechanism.IsAvailable(hookName, height) { - continue - } - - // Grab the hook map - hookMap := mechanism.GetHookMap() - - // Grab the actual hook if it's present - hook, ok := hookMap[hookName] - if !ok { - // hook not found, continue - continue - } - - // Run the hook - if err := hook(hookParam); err != nil { - return fmt.Errorf("error occurred during a call of %s hook in %s: %w", hookName, mechanism.GetType(), err) - } - } - - return nil -} - func (i *backendIBFT) Initialize() error { // register the grpc operator if i.Grpc != nil { @@ -176,18 +177,22 @@ func (i *backendIBFT) Initialize() error { proto.RegisterIbftOperatorServer(i.Grpc, i.operator) } - // Set up the node's validator key - if err := i.createKey(); err != nil { + // start the transport protocol + if err := i.setupTransport(); err != nil { return err } - i.logger.Info("validator key", "addr", i.validatorKeyAddr.String()) + // initialize fork manager + if err := i.forkManager.Initialize(); err != nil { + return err + } - // start the transport protocol - if err := i.setupTransport(); err != nil { + if err := i.updateCurrentModules(i.blockchain.Header().Number + 1); err != nil { return err } + i.logger.Info("validator key", "addr", i.currentSigner.Address().String()) + i.consensus = newIBFT( i.logger.Named("consensus"), i, @@ -197,36 +202,27 @@ func (i *backendIBFT) Initialize() error { // Ensure consensus takes into account user configured block production time i.consensus.ExtendRoundTimeout(i.blockTime) - // Set up the snapshots - if err := i.setupSnapshot(); err != nil { - return err - } - - snap, err := i.getLatestSnapshot() - if err != nil { - return err - } - - i.activeValidatorSet = snap.Set - return nil } // sync runs the syncer in the background to receive blocks from advanced peers func (i *backendIBFT) startSyncing() { - callInsertBlockHook := func(blockNumber uint64) { - if err := i.runHook(InsertBlockHook, blockNumber, blockNumber); err != nil { - i.logger.Error(fmt.Sprintf("Unable to run hook %s, %v", InsertBlockHook, err)) + callInsertBlockHook := func(block *types.Block) bool { + if err := i.currentHooks.PostInsertBlock(block); err != nil { + i.logger.Error("failed to call PostInsertBlock", "height", block.Header.Number, "error", err) + } + + if err := i.updateCurrentModules(block.Number() + 1); err != nil { + i.logger.Error("failed to update sub modules", "height", block.Number()+1, "err", err) } + + i.txpool.ResetWithHeaders(block.Header) + + return false } if err := i.syncer.Sync( - func(block *types.Block) bool { - callInsertBlockHook(block.Number()) - i.txpool.ResetWithHeaders(block.Header) - - return false - }, + callInsertBlockHook, ); err != nil { i.logger.Error("watch sync failed", "err", err) } @@ -253,104 +249,6 @@ func (i *backendIBFT) GetSyncProgression() *progress.Progression { return i.syncer.GetSyncProgression() } -// GetIBFTForks returns IBFT fork configurations from chain config -func GetIBFTForks(ibftConfig map[string]interface{}) ([]IBFTFork, error) { - // no fork, only specifying IBFT type in chain config - if originalType, ok := ibftConfig["type"].(string); ok { - typ, err := ParseType(originalType) - if err != nil { - return nil, err - } - - return []IBFTFork{ - { - Type: typ, - Deployment: nil, - From: common.JSONNumber{Value: 0}, - To: nil, - }, - }, nil - } - - // with forks - if types, ok := ibftConfig["types"].([]interface{}); ok { - bytes, err := json.Marshal(types) - if err != nil { - return nil, err - } - - var forks []IBFTFork - if err := json.Unmarshal(bytes, &forks); err != nil { - return nil, err - } - - return forks, nil - } - - return nil, errors.New("current IBFT type not found") -} - -// setupMechanism reads the current mechanism in params and sets up consensus mechanism -func (i *backendIBFT) setupMechanism() error { - ibftForks, err := GetIBFTForks(i.config.Config) - if err != nil { - return err - } - - i.mechanisms = make([]ConsensusMechanism, len(ibftForks)) - - for idx, fork := range ibftForks { - factory, ok := mechanismBackends[fork.Type] - if !ok { - return fmt.Errorf("consensus mechanism doesn't define: %s", fork.Type) - } - - fork := fork - if i.mechanisms[idx], err = factory(i, &fork); err != nil { - return err - } - } - - return nil -} - -// createKey sets the validator's private key from the secrets manager -func (i *backendIBFT) createKey() error { - if i.validatorKey == nil { - // Check if the validator key is initialized - var key *ecdsa.PrivateKey - - if i.secretsManager.HasSecret(secrets.ValidatorKey) { - // The validator key is present in the secrets manager, load it - validatorKey, readErr := crypto.ReadConsensusKey(i.secretsManager) - if readErr != nil { - return fmt.Errorf("unable to read validator key from Secrets Manager, %w", readErr) - } - - key = validatorKey - } else { - // The validator key is not present in the secrets manager, generate it - validatorKey, validatorKeyEncoded, genErr := crypto.GenerateAndEncodePrivateKey() - if genErr != nil { - return fmt.Errorf("unable to generate validator key for Secrets Manager, %w", genErr) - } - - // Save the key to the secrets manager - saveErr := i.secretsManager.SetSecret(secrets.ValidatorKey, validatorKeyEncoded) - if saveErr != nil { - return fmt.Errorf("unable to save validator key to Secrets Manager, %w", saveErr) - } - - key = validatorKey - } - - i.validatorKey = key - i.validatorKeyAddr = crypto.PubKeyToAddress(&key.PublicKey) - } - - return nil -} - func (i *backendIBFT) startConsensus() { var ( newBlockSub = i.blockchain.SubscribeEvents() @@ -387,7 +285,16 @@ func (i *backendIBFT) startConsensus() { pending = latest + 1 ) - i.updateActiveValidatorSet(latest) + if err := i.updateCurrentModules(pending); err != nil { + i.logger.Error( + "failed to update submodules", + "height", pending, + "err", err, + ) + } + + // Update the No.of validator metric + i.metrics.Validators.Set(float64(i.currentValidators.Len())) isValidator = i.isActiveValidator() @@ -412,30 +319,9 @@ func (i *backendIBFT) startConsensus() { } } +// isActiveValidator returns whether my signer belongs to current validators func (i *backendIBFT) isActiveValidator() bool { - return i.activeValidatorSet.Includes(i.validatorKeyAddr) -} - -func (i *backendIBFT) updateActiveValidatorSet(latestHeight uint64) { - snap := i.getSnapshot(latestHeight) - - i.activeValidatorSet = snap.Set - - // Update the No.of validator metric - i.metrics.Validators.Set(float64(len(snap.Set))) -} - -// shouldWriteTransactions checks if each consensus mechanism accepts a block with transactions at given height -// returns true if all mechanisms accept -// otherwise return false -func (i *backendIBFT) shouldWriteTransactions(height uint64) bool { - for _, m := range i.mechanisms { - if m.ShouldWriteTransactions(height) { - return true - } - } - - return false + return i.currentValidators.Includes(i.currentSigner.Address()) } // updateMetrics will update various metrics based on the given block @@ -457,41 +343,57 @@ func (i *backendIBFT) updateMetrics(block *types.Block) { i.metrics.NumTxs.Set(float64(len(block.Body().Transactions))) } -var ( - errBlockVerificationFailed = errors.New("block verification fail") -) - // isSealing checks if the current node is sealing blocks func (i *backendIBFT) isSealing() bool { return i.sealing } -// verifyHeaderImpl implements the actual header verification logic -func (i *backendIBFT) verifyHeaderImpl(snap *Snapshot, parent, header *types.Header) error { - // ensure the extra data is correctly formatted - if _, err := getIbftExtra(header); err != nil { - return err +// verifyHeaderImpl verifies fields including Extra +// for the past or being proposed header +func (i *backendIBFT) verifyHeaderImpl( + parent, header *types.Header, + headerSigner signer.Signer, + validators validators.Validators, + hooks fork.HooksInterface, + shouldVerifyParentCommittedSeals bool, +) error { + if header.MixHash != signer.IstanbulDigest { + return ErrInvalidMixHash } - if hookErr := i.runHook(VerifyHeadersHook, header.Number, header.Nonce); hookErr != nil { - return hookErr + if header.Sha3Uncles != types.EmptyUncleHash { + return ErrInvalidSha3Uncles } - if header.MixHash != IstanbulDigest { - return fmt.Errorf("invalid mixhash") + // difficulty has to match number + if header.Difficulty != header.Number { + return ErrWrongDifficulty } - if header.Sha3Uncles != types.EmptyUncleHash { - return fmt.Errorf("invalid sha3 uncles") + // ensure the extra data is correctly formatted + if _, err := headerSigner.GetIBFTExtra(header); err != nil { + return err } - // difficulty has to match number - if header.Difficulty != header.Number { - return fmt.Errorf("wrong difficulty") + // verify the ProposerSeal + if err := verifyProposerSeal( + header, + headerSigner, + validators, + ); err != nil { + return err } - // verify the sealer - if err := verifySigner(snap, header); err != nil { + // verify the ParentCommittedSeals + if err := i.verifyParentCommittedSeals( + parent, header, + shouldVerifyParentCommittedSeals, + ); err != nil { + return err + } + + // Additional header verification + if err := hooks.VerifyHeader(header); err != nil { return err } @@ -508,25 +410,40 @@ func (i *backendIBFT) VerifyHeader(header *types.Header) error { ) } - parentSnap := i.getSnapshot(parent.Number) - if parentSnap == nil { - return errParentSnapshotNotFound + headerSigner, validators, hooks, err := getModulesFromForkManager( + i.forkManager, + header.Number, + ) + if err != nil { + return err } - // verify all the header fields + seal - if err := i.verifyHeaderImpl(parentSnap, parent, header); err != nil { + // verify all the header fields + if err := i.verifyHeaderImpl( + parent, + header, + headerSigner, + validators, + hooks, + false, + ); err != nil { return err } - // verify the committed seals - if err := verifyCommittedFields(parentSnap, header, i.quorumSize(header.Number)); err != nil { + // verify the Committed Seals + // CommittedSeals exists only in the finalized header + if err := headerSigner.VerifyCommittedSeals( + header, + validators, + i.quorumSize(header.Number)(validators), + ); err != nil { return err } return nil } -// quorumSize returns a callback that when executed on a ValidatorSet computes +// quorumSize returns a callback that when executed on a Validators computes // number of votes required to reach quorum based on the size of the set. // The blockNumber argument indicates which formula was used to calculate the result (see PRs #513, #549) func (i *backendIBFT) quorumSize(blockNumber uint64) QuorumImplementation { @@ -539,26 +456,32 @@ func (i *backendIBFT) quorumSize(blockNumber uint64) QuorumImplementation { // ProcessHeaders updates the snapshot based on previously verified headers func (i *backendIBFT) ProcessHeaders(headers []*types.Header) error { - return i.processHeaders(headers) + for _, header := range headers { + hooks := i.forkManager.GetHooks(header.Number) + + if err := hooks.ProcessHeader(header); err != nil { + return err + } + } + + return nil } // GetBlockCreator retrieves the block signer from the extra data field func (i *backendIBFT) GetBlockCreator(header *types.Header) (types.Address, error) { - return ecrecoverProposer(header) -} - -// PreStateCommit a hook to be called before finalizing state transition on inserting block -func (i *backendIBFT) PreStateCommit(header *types.Header, txn *state.Transition) error { - params := &preStateCommitHookParams{ - header: header, - txn: txn, + signer, err := i.forkManager.GetSigner(header.Number) + if err != nil { + return types.ZeroAddress, err } - if err := i.runHook(PreStateCommitHook, header.Number, params); err != nil { - return err - } + return signer.EcrecoverFromHeader(header) +} - return nil +// PreCommitState a hook to be called before finalizing state transition on inserting block +func (i *backendIBFT) PreCommitState(header *types.Header, txn *state.Transition) error { + hooks := i.forkManager.GetHooks(header.Number) + + return hooks.PreCommitState(header, txn) } // GetEpoch returns the current epoch @@ -579,19 +502,132 @@ func (i *backendIBFT) IsLastOfEpoch(number uint64) bool { func (i *backendIBFT) Close() error { close(i.closeCh) - if i.config.Path != "" { - err := i.store.saveToPath(i.config.Path) - - if err != nil { + if i.syncer != nil { + if err := i.syncer.Close(); err != nil { return err } } - if i.syncer != nil { - if err := i.syncer.Close(); err != nil { + if i.forkManager != nil { + if err := i.forkManager.Close(); err != nil { return err } } return nil } + +// SetHeaderHash updates hash calculation function for IBFT +func (i *backendIBFT) SetHeaderHash() { + types.HeaderHash = func(h *types.Header) types.Hash { + signer, err := i.forkManager.GetSigner(h.Number) + if err != nil { + return types.ZeroHash + } + + hash, err := signer.CalculateHeaderHash(h) + if err != nil { + return types.ZeroHash + } + + return hash + } +} + +// updateCurrentModules updates Signer, Hooks, and Validators +// that are used at specified height +// by fetching from ForkManager +func (i *backendIBFT) updateCurrentModules(height uint64) error { + lastSigner := i.currentSigner + + signer, validators, hooks, err := getModulesFromForkManager(i.forkManager, height) + if err != nil { + return err + } + + i.currentSigner = signer + i.currentValidators = validators + i.currentHooks = hooks + + i.logFork(lastSigner, signer) + + return nil +} + +// logFork logs validation type switch +func (i *backendIBFT) logFork( + lastSigner, signer signer.Signer, +) { + if lastSigner != nil && signer != nil && lastSigner.Type() != signer.Type() { + i.logger.Info("IBFT validation type switched", "old", lastSigner.Type(), "new", signer.Type()) + } +} + +func (i *backendIBFT) verifyParentCommittedSeals( + parent, header *types.Header, + shouldVerifyParentCommittedSeals bool, +) error { + if parent.IsGenesis() { + return nil + } + + parentSigner, parentValidators, _, err := getModulesFromForkManager( + i.forkManager, + parent.Number, + ) + + if err != nil { + return err + } + + // if shouldVerifyParentCommittedSeals is false, skip the verification + // when header doesn't have Parent Committed Seals (Backward Compatibility) + return parentSigner.VerifyParentCommittedSeals( + parent, + header, + parentValidators, + i.quorumSize(parent.Number)(parentValidators), + shouldVerifyParentCommittedSeals, + ) +} + +// getModulesFromForkManager is a helper function to get all modules from ForkManager +func getModulesFromForkManager(forkManager forkManagerInterface, height uint64) ( + signer.Signer, + validators.Validators, + fork.HooksInterface, + error, +) { + signer, err := forkManager.GetSigner(height) + if err != nil { + return nil, nil, nil, err + } + + validators, err := forkManager.GetValidators(height) + if err != nil { + return nil, nil, nil, err + } + + hooks := forkManager.GetHooks(height) + + return signer, validators, hooks, nil +} + +// verifyProposerSeal verifies ProposerSeal in IBFT Extra of header +// and make sure signer belongs to validators +func verifyProposerSeal( + header *types.Header, + signer signer.Signer, + validators validators.Validators, +) error { + proposer, err := signer.EcrecoverFromHeader(header) + if err != nil { + return err + } + + if !validators.Includes(proposer) { + return ErrProposerSealByNonValidator + } + + return nil +} diff --git a/consensus/ibft/messages.go b/consensus/ibft/messages.go index b1e9f0dafc..f772a5807f 100644 --- a/consensus/ibft/messages.go +++ b/consensus/ibft/messages.go @@ -4,7 +4,6 @@ import ( "google.golang.org/protobuf/proto" protoIBFT "github.com/0xPolygon/go-ibft/messages/proto" - "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" ) @@ -14,13 +13,10 @@ func (i *backendIBFT) signMessage(msg *protoIBFT.Message) *protoIBFT.Message { return nil } - sig, err := crypto.Sign(i.validatorKey, crypto.Keccak256(raw)) - if err != nil { + if msg.Signature, err = i.currentSigner.SignIBFTMessage(raw); err != nil { return nil } - msg.Signature = sig - return msg } @@ -68,7 +64,7 @@ func (i *backendIBFT) BuildPrepareMessage(proposalHash []byte, view *protoIBFT.V } func (i *backendIBFT) BuildCommitMessage(proposalHash []byte, view *protoIBFT.View) *protoIBFT.Message { - seal, err := writeCommittedSeal(i.validatorKey, proposalHash) + committedSeal, err := i.currentSigner.CreateCommittedSeal(proposalHash) if err != nil { i.logger.Error("Unable to build commit message, %v", err) @@ -82,7 +78,7 @@ func (i *backendIBFT) BuildCommitMessage(proposalHash []byte, view *protoIBFT.Vi Payload: &protoIBFT.Message_CommitData{ CommitData: &protoIBFT.CommitMessage{ ProposalHash: proposalHash, - CommittedSeal: seal, + CommittedSeal: committedSeal, }, }, } diff --git a/consensus/ibft/operator_service.go b/consensus/ibft/operator_service.go index 0e6e19b0df..82f1c38217 100644 --- a/consensus/ibft/operator_service.go +++ b/consensus/ibft/operator_service.go @@ -2,163 +2,239 @@ package ibft import ( "context" + "errors" "fmt" - "sync" "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" empty "google.golang.org/protobuf/types/known/emptypb" ) +var ( + ErrVotingNotSupported = errors.New("voting is not supported") + ErrHeaderNotFound = errors.New("header not found") +) + type operator struct { - ibft *backendIBFT + proto.UnimplementedIbftOperatorServer - candidatesLock sync.Mutex - candidates []*proto.Candidate + ibft *backendIBFT +} - proto.UnimplementedIbftOperatorServer +// Votable is an interface of the ValidatorStore with vote function +type Votable interface { + Votes(uint64) ([]*store.Vote, error) + Candidates() []*store.Candidate + Propose(validators.Validator, bool, types.Address) error } // Status returns the status of the IBFT client func (o *operator) Status(ctx context.Context, req *empty.Empty) (*proto.IbftStatusResp, error) { - resp := &proto.IbftStatusResp{ - Key: o.ibft.validatorKeyAddr.String(), + signer, err := o.getLatestSigner() + if err != nil { + return nil, err } - return resp, nil + return &proto.IbftStatusResp{ + Key: signer.Address().String(), + }, nil } -// getNextCandidate returns a candidate from the snapshot -func (o *operator) getNextCandidate(snap *Snapshot) *proto.Candidate { - o.candidatesLock.Lock() - defer o.candidatesLock.Unlock() - - // first, we need to remove any candidates that have already been - // selected as validators - for i := 0; i < len(o.candidates); i++ { - addr := types.StringToAddress(o.candidates[i].Address) - - // Define the delete callback method - deleteFn := func() { - o.candidates = append(o.candidates[:i], o.candidates[i+1:]...) - i-- - } - - // Check if the candidate is already in the validator set, and wants to be added - if o.candidates[i].Auth && snap.Set.Includes(addr) { - deleteFn() - - continue - } +// GetSnapshot returns the snapshot, based on the passed in request +func (o *operator) GetSnapshot(ctx context.Context, req *proto.SnapshotReq) (*proto.Snapshot, error) { + height := req.Number + if req.Latest { + height = o.ibft.blockchain.Header().Number + } - // Check if the candidate is not in the validator set, and wants to be removed - if !o.candidates[i].Auth && !snap.Set.Includes(addr) { - deleteFn() - } + header, ok := o.ibft.blockchain.GetHeaderByNumber(height) + if !ok { + return nil, ErrHeaderNotFound } - var candidate *proto.Candidate + validatorsStore, err := o.ibft.forkManager.GetValidatorStore(height) + if err != nil { + return nil, err + } - // now pick the first candidate that has not received a vote yet - for _, c := range o.candidates { - addr := types.StringToAddress(c.Address) + validators, err := o.ibft.forkManager.GetValidators(height) + if err != nil { + return nil, err + } - count := snap.Count(func(v *Vote) bool { - return v.Address == addr && v.Validator == o.ibft.validatorKeyAddr - }) + resp := &proto.Snapshot{ + Number: height, + Hash: header.Hash.String(), + Validators: validatorsToProtoValidators(validators), + } - if count == 0 { - // Candidate found - candidate = c + votes, err := getVotes(validatorsStore, height) + if err != nil { + return nil, err + } - break - } + if votes == nil { + // current ValidatorStore doesn't have voting function + return resp, nil } - return candidate + resp.Votes = votesToProtoVotes(votes) + + return resp, nil } -// GetSnapshot returns the snapshot, based on the passed in request -func (o *operator) GetSnapshot(ctx context.Context, req *proto.SnapshotReq) (*proto.Snapshot, error) { - var snap *Snapshot +// Propose proposes a new candidate to be added / removed from the validator set +func (o *operator) Propose(ctx context.Context, req *proto.Candidate) (*empty.Empty, error) { + votableSet, err := o.getVotableValidatorStore() + if err != nil { + return nil, err + } - var err error + candidate, err := o.parseCandidate(req) + if err != nil { + return nil, err + } - if req.Latest { - snap, err = o.ibft.getLatestSnapshot() - } else { - snap = o.ibft.getSnapshot(req.Number) - if snap == nil { - err = errSnapshotNotFound - } + if err := votableSet.Propose(candidate, req.Auth, o.ibft.currentSigner.Address()); err != nil { + return nil, err } + return &empty.Empty{}, nil +} + +// Candidates returns the validator candidates list +func (o *operator) Candidates(ctx context.Context, req *empty.Empty) (*proto.CandidatesResp, error) { + votableValSet, err := o.getVotableValidatorStore() if err != nil { return nil, err } - resp := snap.ToProto() + candidates := votableValSet.Candidates() - return resp, nil + return &proto.CandidatesResp{ + Candidates: candidatesToProtoCandidates(candidates), + }, nil } -// Propose proposes a new candidate to be added / removed from the validator set -func (o *operator) Propose(ctx context.Context, req *proto.Candidate) (*empty.Empty, error) { - var addr types.Address - if err := addr.UnmarshalText([]byte(req.Address)); err != nil { +// parseCandidate parses proto.Candidate and maps to validator +func (o *operator) parseCandidate(req *proto.Candidate) (validators.Validator, error) { + signer, err := o.getLatestSigner() + if err != nil { return nil, err } - // check if the candidate is already there - o.candidatesLock.Lock() - defer o.candidatesLock.Unlock() - - for _, c := range o.candidates { - if c.Address == req.Address { - return nil, fmt.Errorf("already a candidate") + switch signer.Type() { + case validators.ECDSAValidatorType: + return &validators.ECDSAValidator{ + Address: types.StringToAddress(req.Address), + }, nil + + case validators.BLSValidatorType: + // safe check + if req.Auth { + // BLS public key is necessary but the command is not required + if req.BlsPubkey == nil { + return nil, errors.New("BLS public key required") + } + + if _, err := crypto.UnmarshalBLSPublicKey(req.BlsPubkey); err != nil { + return nil, err + } } + + // BLS Public Key doesn't have to be given in case of removal + return &validators.BLSValidator{ + Address: types.StringToAddress(req.Address), + BLSPublicKey: req.BlsPubkey, + }, nil } - snap, err := o.ibft.getLatestSnapshot() + return nil, fmt.Errorf("invalid validator type: %s", signer.Type()) +} + +// getVotableValidatorStore gets current validator set and convert its type to Votable +func (o *operator) getVotableValidatorStore() (Votable, error) { + valSet, err := o.ibft.forkManager.GetValidatorStore(o.ibft.blockchain.Header().Number) if err != nil { return nil, err } - // safe checks - if req.Auth { - if snap.Set.Includes(addr) { - return nil, fmt.Errorf("the candidate is already a validator") - } + + votableValSet, ok := valSet.(Votable) + if !ok { + return nil, ErrVotingNotSupported } - if !req.Auth { - if !snap.Set.Includes(addr) { - return nil, fmt.Errorf("cannot remove a validator if they're not in the snapshot") - } + return votableValSet, nil +} + +// getLatestSigner gets the latest signer IBFT uses +func (o *operator) getLatestSigner() (signer.Signer, error) { + if o.ibft.currentSigner != nil { + return o.ibft.currentSigner, nil } - // check if we have already voted for this candidate - count := snap.Count(func(v *Vote) bool { - return v.Address == addr && v.Validator == o.ibft.validatorKeyAddr - }) - if count == 1 { - return nil, fmt.Errorf("already voted for this address") + return o.ibft.forkManager.GetSigner(o.ibft.blockchain.Header().Number) +} + +// validatorsToProtoValidators converts validators to response of validators +func validatorsToProtoValidators(validators validators.Validators) []*proto.Snapshot_Validator { + protoValidators := make([]*proto.Snapshot_Validator, validators.Len()) + + for idx := 0; idx < validators.Len(); idx++ { + validator := validators.At(uint64(idx)) + + protoValidators[idx] = &proto.Snapshot_Validator{ + Type: string(validator.Type()), + Address: validator.Addr().String(), + Data: validator.Bytes(), + } } - o.candidates = append(o.candidates, req) + return protoValidators +} - return &empty.Empty{}, nil +// votesToProtoVotes converts votes to response of votes +func votesToProtoVotes(votes []*store.Vote) []*proto.Snapshot_Vote { + protoVotes := make([]*proto.Snapshot_Vote, len(votes)) + + for idx := range votes { + protoVotes[idx] = &proto.Snapshot_Vote{ + Validator: votes[idx].Validator.String(), + Proposed: votes[idx].Candidate.String(), + Auth: votes[idx].Authorize, + } + } + + return protoVotes } -// Candidates returns the validator candidates list -func (o *operator) Candidates(ctx context.Context, req *empty.Empty) (*proto.CandidatesResp, error) { - o.candidatesLock.Lock() - defer o.candidatesLock.Unlock() +func candidatesToProtoCandidates(candidates []*store.Candidate) []*proto.Candidate { + protoCandidates := make([]*proto.Candidate, len(candidates)) + + for idx, candidate := range candidates { + protoCandidates[idx] = &proto.Candidate{ + Address: candidate.Validator.Addr().String(), + Auth: candidate.Authorize, + } - resp := &proto.CandidatesResp{ - Candidates: []*proto.Candidate{}, + if blsVal, ok := candidate.Validator.(*validators.BLSValidator); ok { + protoCandidates[idx].BlsPubkey = blsVal.BLSPublicKey + } } - resp.Candidates = append(resp.Candidates, o.candidates...) + return protoCandidates +} - return resp, nil +// getVotes gets votes from validator store only if store supports voting +func getVotes(validatorStore store.ValidatorStore, height uint64) ([]*store.Vote, error) { + votableStore, ok := validatorStore.(Votable) + if !ok { + return nil, nil + } + + return votableStore.Votes(height) } diff --git a/consensus/ibft/operator_service_test.go b/consensus/ibft/operator_service_test.go deleted file mode 100644 index a88dabd687..0000000000 --- a/consensus/ibft/operator_service_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package ibft - -import ( - "context" - "testing" - - "github.com/0xPolygon/polygon-edge/consensus" - - "github.com/0xPolygon/polygon-edge/blockchain" - "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" - "github.com/0xPolygon/polygon-edge/types" - "github.com/stretchr/testify/assert" -) - -func TestOperator_GetNextCandidate(t *testing.T) { - // we cannot vote if there is already a pending vote for our proposal - pool := newTesterAccountPool() - pool.add("A", "B", "C") - - ibft := &backendIBFT{ - validatorKeyAddr: pool.get("A").Address(), - } - - snap := &Snapshot{ - Set: pool.ValidatorSet(), - Votes: []*Vote{ - { - Validator: pool.get("A").Address(), - Address: pool.get("B").Address(), - }, - }, - } - - o := &operator{ - ibft: ibft, - candidates: []*proto.Candidate{ - { - Address: pool.get("B").Address().String(), - Auth: false, - }, - }, - } - - // it has already voted once, it cannot vote again - assert.Nil(t, o.getNextCandidate(snap)) - - snap.Votes = nil - - // there are no votes so it can vote - assert.NotNil(t, o.getNextCandidate(snap)) - - snap.Set = []types.Address{} - - // it was a removal and since the candidate is not on the set anymore - // is removed from the candidates list - assert.Nil(t, o.getNextCandidate(snap)) - assert.Len(t, o.candidates, 0) - - // Try to insert now a new candidate - o.candidates = []*proto.Candidate{ - { - Address: pool.get("B").Address().String(), - Auth: true, - }, - } - - assert.NotNil(t, o.getNextCandidate(snap)) - - // add the new candidate to the set - snap.Set = pool.ValidatorSet() - - // now the candidate is on the new set so we have to remove - // the candidate - assert.Nil(t, o.getNextCandidate(snap)) - assert.Len(t, o.candidates, 0) -} - -func TestOperator_Propose(t *testing.T) { - pool := newTesterAccountPool() - pool.add("A", "B", "C") - - ibft := &backendIBFT{ - blockchain: blockchain.TestBlockchain(t, pool.genesis()), - config: &consensus.Config{}, - epochSize: DefaultEpochSize, - } - assert.NoError(t, ibft.setupSnapshot()) - - o := &operator{ibft: ibft} - - pool.add("X") - - // we cannot propose to add a validator already in the set - _, err := o.Propose(context.Background(), &proto.Candidate{ - Address: pool.get("A").Address().String(), - Auth: true, - }) - assert.Error(t, err) - - // we cannot propose remove a validator that is not part of the set - _, err = o.Propose(context.Background(), &proto.Candidate{ - Address: pool.get("X").Address().String(), - Auth: false, - }) - assert.Error(t, err) - - // we can send either add or del proposals - _, err = o.Propose(context.Background(), &proto.Candidate{ - Address: pool.get("X").Address().String(), - Auth: true, - }) - assert.NoError(t, err) - assert.Len(t, o.candidates, 1) - - _, err = o.Propose(context.Background(), &proto.Candidate{ - Address: pool.get("A").Address().String(), - Auth: false, - }) - assert.NoError(t, err) - assert.Len(t, o.candidates, 2) - - // we cannot send the same proposal twice - _, err = o.Propose(context.Background(), &proto.Candidate{ - Address: pool.get("A").Address().String(), - Auth: false, - }) - assert.Error(t, err) -} diff --git a/consensus/ibft/poa.go b/consensus/ibft/poa.go deleted file mode 100644 index e5df4391e5..0000000000 --- a/consensus/ibft/poa.go +++ /dev/null @@ -1,235 +0,0 @@ -package ibft - -import ( - "errors" - "fmt" - - "github.com/0xPolygon/polygon-edge/types" -) - -var ( - // Magic nonce number to vote on adding a new validator - nonceAuthVote = types.Nonce{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} - - // Magic nonce number to vote on removing a validator. - nonceDropVote = types.Nonce{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -) - -var ( - ErrInvalidNonce = errors.New("invalid nonce specified") -) - -// PoAMechanism defines specific hooks for the Proof of Authority IBFT mechanism -type PoAMechanism struct { - BaseConsensusMechanism -} - -// PoAFactory initializes the required data -// for the Proof of Authority mechanism -func PoAFactory(ibft *backendIBFT, params *IBFTFork) (ConsensusMechanism, error) { - poa := &PoAMechanism{ - BaseConsensusMechanism: BaseConsensusMechanism{ - mechanismType: PoA, - ibft: ibft, - }, - } - - if err := poa.initializeParams(params); err != nil { - return nil, err - } - - poa.initializeHookMap() - - return poa, nil -} - -// IsAvailable returns indicates if mechanism should be called at given height -func (poa *PoAMechanism) IsAvailable(hookType HookType, height uint64) bool { - switch hookType { - case VerifyHeadersHook, ProcessHeadersHook, CandidateVoteHook: - return poa.IsInRange(height) - default: - return false - } -} - -// verifyHeadersHook verifies that the header nonce conforms to the IBFT PoA proposal format -func (poa *PoAMechanism) verifyHeadersHook(nonceParam interface{}) error { - // Cast the param to the nonce - nonce, ok := nonceParam.(types.Nonce) - if !ok { - return ErrInvalidHookParam - } - - // Check the nonce format. - // The nonce field must have either an AUTH or DROP vote value. - // Block nonce values are not taken into account when the Miner field is set to zeroes, indicating - // no vote casting is taking place within a block - if nonce != nonceDropVote && nonce != nonceAuthVote { - return ErrInvalidNonce - } - - return nil -} - -// processHeadersHookParams are the params passed into the processHeadersHook -type processHeadersHookParams struct { - header *types.Header - snap *Snapshot - parentSnap *Snapshot - proposer types.Address - saveSnap func(h *types.Header) -} - -// processHeadersHook does the required logic for PoA header processing -func (poa *PoAMechanism) processHeadersHook(hookParam interface{}) error { - // Cast the params to processHeadersHookParams - params, ok := hookParam.(*processHeadersHookParams) - if !ok { - return ErrInvalidHookParam - } - - number := params.header.Number - if number%poa.ibft.epochSize == 0 { - // during a checkpoint block, we reset the votes - // and there cannot be any proposals - params.snap.Votes = nil - params.saveSnap(params.header) - - // remove in-memory snapshots from two epochs before this one - epoch := int(number/poa.ibft.epochSize) - 2 - if epoch > 0 { - purgeBlock := uint64(epoch) * poa.ibft.epochSize - poa.ibft.store.deleteLower(purgeBlock) - } - - return nil - } - - // if we have a miner address, this might be a vote - if params.header.Miner == types.ZeroAddress { - return nil - } - - // the nonce selects the action - var authorize bool - - switch params.header.Nonce { - case nonceAuthVote: - authorize = true - case nonceDropVote: - authorize = false - default: - return fmt.Errorf("incorrect vote nonce") - } - - // validate the vote - if authorize { - // we can only authorize if they are not on the validators list - if params.snap.Set.Includes(params.header.Miner) { - return nil - } - } else { - // we can only remove if they are part of the validators list - if !params.snap.Set.Includes(params.header.Miner) { - return nil - } - } - - voteCount := params.snap.Count(func(v *Vote) bool { - return v.Validator == params.proposer && v.Address == params.header.Miner - }) - - if voteCount > 1 { - // there can only be one vote per validator per address - return fmt.Errorf("more than one proposal per validator per address found") - } - - if voteCount == 0 { - // cast the new vote since there is no one yet - params.snap.Votes = append(params.snap.Votes, &Vote{ - Validator: params.proposer, - Address: params.header.Miner, - Authorize: authorize, - }) - } - - // check the tally for the proposed validator - tally := params.snap.Count(func(v *Vote) bool { - return v.Address == params.header.Miner - }) - - // If more than a half of all validators voted - if tally > params.snap.Set.Len()/2 { - if authorize { - // add the candidate to the validators list - params.snap.Set.Add(params.header.Miner) - } else { - // remove the candidate from the validators list - params.snap.Set.Del(params.header.Miner) - - // remove any votes casted by the removed validator - params.snap.RemoveVotes(func(v *Vote) bool { - return v.Validator == params.header.Miner - }) - } - - // remove all the votes that promoted this validator - params.snap.RemoveVotes(func(v *Vote) bool { - return v.Address == params.header.Miner - }) - } - - return nil -} - -// candidateVoteHookParams are the params passed into the candidateVoteHook -type candidateVoteHookParams struct { - header *types.Header - snap *Snapshot -} - -// candidateVoteHook checks if any candidate is up for voting by the operator -// and casts a vote in the Nonce field of the block being built -func (poa *PoAMechanism) candidateVoteHook(hookParams interface{}) error { - // Cast the params to candidateVoteHookParams - params, ok := hookParams.(*candidateVoteHookParams) - if !ok { - return ErrInvalidHookParam - } - - // try to pick a candidate - if candidate := poa.ibft.operator.getNextCandidate(params.snap); candidate != nil { - params.header.Miner = types.StringToAddress(candidate.Address) - if candidate.Auth { - params.header.Nonce = nonceAuthVote - } else { - params.header.Nonce = nonceDropVote - } - } - - return nil -} - -// initializeHookMap registers the hooks that the PoA mechanism -// should have -func (poa *PoAMechanism) initializeHookMap() { - // Create the hook map - poa.hookMap = make(map[HookType]func(interface{}) error) - - // Register the VerifyHeadersHook - poa.hookMap[VerifyHeadersHook] = poa.verifyHeadersHook - - // Register the ProcessHeadersHook - poa.hookMap[ProcessHeadersHook] = poa.processHeadersHook - - // Register the CandidateVoteHook - poa.hookMap[CandidateVoteHook] = poa.candidateVoteHook -} - -// ShouldWriteTransactions indicates if transactions should be written to a block -func (poa *PoAMechanism) ShouldWriteTransactions(blockNumber uint64) bool { - // The PoA mechanism doesn't have special cases where transactions - // shouldn't be written to a block - return poa.IsInRange(blockNumber) -} diff --git a/consensus/ibft/pos.go b/consensus/ibft/pos.go deleted file mode 100644 index 83a857c164..0000000000 --- a/consensus/ibft/pos.go +++ /dev/null @@ -1,216 +0,0 @@ -package ibft - -import ( - "errors" - "fmt" - - "github.com/0xPolygon/polygon-edge/contracts/staking" - stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" - "github.com/0xPolygon/polygon-edge/state" - "github.com/0xPolygon/polygon-edge/types" -) - -// PoSMechanism defines specific hooks for the Proof of Stake IBFT mechanism -type PoSMechanism struct { - BaseConsensusMechanism - // Params - ContractDeployment uint64 // The height when deploying staking contract - MaxValidatorCount uint64 - MinValidatorCount uint64 -} - -// PoSFactory initializes the required data -// for the Proof of Stake mechanism -func PoSFactory(ibft *backendIBFT, params *IBFTFork) (ConsensusMechanism, error) { - pos := &PoSMechanism{ - BaseConsensusMechanism: BaseConsensusMechanism{ - mechanismType: PoS, - ibft: ibft, - }, - } - - if err := pos.initializeParams(params); err != nil { - return nil, err - } - - pos.initializeHookMap() - - return pos, nil -} - -// IsAvailable returns indicates if mechanism should be called at given height -func (pos *PoSMechanism) IsAvailable(hookType HookType, height uint64) bool { - switch hookType { - case VerifyBlockHook: - return pos.IsInRange(height) - case PreStateCommitHook: - // deploy contract on ContractDeployment - return height == pos.ContractDeployment - case InsertBlockHook: - // update validators when the one before the beginning or the end of epoch - return height+1 == pos.From || pos.IsInRange(height) && pos.ibft.IsLastOfEpoch(height) - default: - return false - } -} - -// initializeParams initializes mechanism parameters from chain config -func (pos *PoSMechanism) initializeParams(params *IBFTFork) error { - if err := pos.BaseConsensusMechanism.initializeParams(params); err != nil { - return err - } - - if pos.From != 0 { - if params.Deployment == nil { - return errors.New(`"deployment" must be specified in PoS fork`) - } - - if params.Deployment.Value > pos.From { - return fmt.Errorf( - `"deployment" must be less than or equal to "from": deployment=%d, from=%d`, - params.Deployment.Value, - pos.From, - ) - } - - pos.ContractDeployment = params.Deployment.Value - - if params.MaxValidatorCount == nil { - pos.MaxValidatorCount = stakingHelper.MaxValidatorCount - } else { - pos.MaxValidatorCount = params.MaxValidatorCount.Value - } - - if params.MinValidatorCount == nil { - pos.MinValidatorCount = stakingHelper.MinValidatorCount - } else { - pos.MinValidatorCount = params.MinValidatorCount.Value - } - } - - return nil -} - -// insertBlockHook checks if the block is the last block of the epoch, -// in order to update the validator set -func (pos *PoSMechanism) insertBlockHook(numberParam interface{}) error { - headerNumber, ok := numberParam.(uint64) - if !ok { - return ErrInvalidHookParam - } - - return pos.updateValidators(headerNumber) -} - -// verifyBlockHook checks if the block is an epoch block and if it has any transactions -func (pos *PoSMechanism) verifyBlockHook(blockParam interface{}) error { - block, ok := blockParam.(*types.Block) - if !ok { - return ErrInvalidHookParam - } - - if pos.ibft.IsLastOfEpoch(block.Number()) && len(block.Transactions) > 0 { - return errBlockVerificationFailed - } - - return nil -} - -// preStateCommitHookParams are the params passed into the preStateCommitHook -type preStateCommitHookParams struct { - header *types.Header - txn *state.Transition -} - -// verifyBlockHook checks if the block is an epoch block and if it has any transactions -func (pos *PoSMechanism) preStateCommitHook(rawParams interface{}) error { - params, ok := rawParams.(*preStateCommitHookParams) - if !ok { - return ErrInvalidHookParam - } - - // Deploy Staking contract - contractState, err := stakingHelper.PredeployStakingSC(nil, stakingHelper.PredeployParams{ - MinValidatorCount: pos.MinValidatorCount, - MaxValidatorCount: pos.MaxValidatorCount, - }) - if err != nil { - return err - } - - if err := params.txn.SetAccountDirectly(staking.AddrStakingContract, contractState); err != nil { - return err - } - - return nil -} - -// initializeHookMap registers the hooks that the PoS mechanism -// should have -func (pos *PoSMechanism) initializeHookMap() { - // Create the hook map - pos.hookMap = make(map[HookType]func(interface{}) error) - - // Register the InsertBlockHook - pos.hookMap[InsertBlockHook] = pos.insertBlockHook - - // Register the VerifyBlockHook - pos.hookMap[VerifyBlockHook] = pos.verifyBlockHook - - // Register the PreStateCommitHook - pos.hookMap[PreStateCommitHook] = pos.preStateCommitHook -} - -// ShouldWriteTransactions indicates if transactions should be written to a block -func (pos *PoSMechanism) ShouldWriteTransactions(blockNumber uint64) bool { - // Epoch blocks should be empty - return pos.IsInRange(blockNumber) && !pos.ibft.IsLastOfEpoch(blockNumber) -} - -// getNextValidators is a helper function for fetching the validator set -// from the Staking SC -func (pos *PoSMechanism) getNextValidators(header *types.Header) (ValidatorSet, error) { - transition, err := pos.ibft.executor.BeginTxn(header.StateRoot, header, types.ZeroAddress) - if err != nil { - return nil, err - } - - return staking.QueryValidators(transition, pos.ibft.validatorKeyAddr) -} - -// updateSnapshotValidators updates validators in snapshot at given height -func (pos *PoSMechanism) updateValidators(num uint64) error { - header, ok := pos.ibft.blockchain.GetHeaderByNumber(num) - if !ok { - return errors.New("header not found") - } - - validators, err := pos.getNextValidators(header) - if err != nil { - return err - } - - snap := pos.ibft.getSnapshot(header.Number) - if snap == nil { - return errSnapshotNotFound - } - - if snap == nil { - return fmt.Errorf("cannot find snapshot at %d", header.Number) - } - - if !snap.Set.Equal(&validators) { - newSnap := snap.Copy() - newSnap.Set = validators - newSnap.Number = header.Number - newSnap.Hash = header.Hash.String() - - if snap.Number != header.Number { - pos.ibft.store.add(newSnap) - } else { - pos.ibft.store.replace(newSnap) - } - } - - return nil -} diff --git a/consensus/ibft/pos_test.go b/consensus/ibft/pos_test.go deleted file mode 100644 index 27b1d019a1..0000000000 --- a/consensus/ibft/pos_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package ibft - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -const ( - TestEpochSize = 10 -) - -func TestGetEpoch(t *testing.T) { - tests := []struct { - num uint64 - epoch uint64 - }{ - // genesis - { - num: 0, - epoch: 0, - }, - // first number - { - num: 1, - epoch: 1, - }, - { - num: 5, - epoch: 1, - }, - // end of first epoch - { - num: 10, - epoch: 1, - }, - // first of second epoch - { - num: 11, - epoch: 2, - }, - } - - for _, tt := range tests { - name := fmt.Sprintf("GetEpoch should return %d for number %d", tt.epoch, tt.num) - t.Run(name, func(t *testing.T) { - ibft := &backendIBFT{ - epochSize: TestEpochSize, - } - res := ibft.GetEpoch(tt.num) - assert.Equal(t, tt.epoch, res) - }) - } -} - -func TestIsFirstOfEpoch(t *testing.T) { - tests := []struct { - num uint64 - isFirst bool - }{ - // genesis - { - num: 0, - isFirst: false, - }, - // first number - { - num: 1, - isFirst: true, - }, - { - num: 5, - isFirst: false, - }, - // end of first epoch - { - num: 10, - isFirst: false, - }, - // first of second epoch - { - num: 11, - isFirst: true, - }, - } - - for _, tt := range tests { - name := fmt.Sprintf("IsFirstOfEpoch should return %t for number %d", tt.isFirst, tt.num) - t.Run(name, func(t *testing.T) { - ibft := &backendIBFT{ - epochSize: TestEpochSize, - } - assert.Equal(t, tt.isFirst, tt.num%ibft.epochSize == 1) - }) - } -} - -func TestIsLastOfEpoch(t *testing.T) { - tests := []struct { - num uint64 - isLast bool - }{ - // genesis - { - num: 0, - isLast: false, - }, - // first number - { - num: 1, - isLast: false, - }, - { - num: 5, - isLast: false, - }, - // end of first epoch - { - num: 10, - isLast: true, - }, - // first of second epoch - { - num: 11, - isLast: false, - }, - // last of second epoch - { - num: 20, - isLast: true, - }, - } - - for _, tt := range tests { - name := fmt.Sprintf("IsLastOfEpoch should return %t for number %d", tt.isLast, tt.num) - t.Run(name, func(t *testing.T) { - ibft := &backendIBFT{ - epochSize: TestEpochSize, - } - res := ibft.IsLastOfEpoch(tt.num) - assert.Equal(t, tt.isLast, res) - }) - } -} diff --git a/consensus/ibft/proto/ibft_operator.pb.go b/consensus/ibft/proto/ibft_operator.pb.go index 72ecfd312d..8504770798 100644 --- a/consensus/ibft/proto/ibft_operator.pb.go +++ b/consensus/ibft/proto/ibft_operator.pb.go @@ -1,15 +1,15 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 -// protoc v3.21.3 -// source: ibft_operator.proto +// protoc-gen-go v1.28.1 +// protoc v3.12.4 +// source: consensus/ibft/proto/ibft_operator.proto package proto import ( + empty "github.com/golang/protobuf/ptypes/empty" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" ) @@ -32,7 +32,7 @@ type IbftStatusResp struct { func (x *IbftStatusResp) Reset() { *x = IbftStatusResp{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[0] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -45,7 +45,7 @@ func (x *IbftStatusResp) String() string { func (*IbftStatusResp) ProtoMessage() {} func (x *IbftStatusResp) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[0] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -58,7 +58,7 @@ func (x *IbftStatusResp) ProtoReflect() protoreflect.Message { // Deprecated: Use IbftStatusResp.ProtoReflect.Descriptor instead. func (*IbftStatusResp) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{0} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{0} } func (x *IbftStatusResp) GetKey() string { @@ -80,7 +80,7 @@ type SnapshotReq struct { func (x *SnapshotReq) Reset() { *x = SnapshotReq{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[1] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -93,7 +93,7 @@ func (x *SnapshotReq) String() string { func (*SnapshotReq) ProtoMessage() {} func (x *SnapshotReq) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[1] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -106,7 +106,7 @@ func (x *SnapshotReq) ProtoReflect() protoreflect.Message { // Deprecated: Use SnapshotReq.ProtoReflect.Descriptor instead. func (*SnapshotReq) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{1} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{1} } func (x *SnapshotReq) GetLatest() bool { @@ -137,7 +137,7 @@ type Snapshot struct { func (x *Snapshot) Reset() { *x = Snapshot{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[2] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -150,7 +150,7 @@ func (x *Snapshot) String() string { func (*Snapshot) ProtoMessage() {} func (x *Snapshot) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[2] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -163,7 +163,7 @@ func (x *Snapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use Snapshot.ProtoReflect.Descriptor instead. func (*Snapshot) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{2} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{2} } func (x *Snapshot) GetValidators() []*Snapshot_Validator { @@ -206,7 +206,7 @@ type ProposeReq struct { func (x *ProposeReq) Reset() { *x = ProposeReq{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[3] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -219,7 +219,7 @@ func (x *ProposeReq) String() string { func (*ProposeReq) ProtoMessage() {} func (x *ProposeReq) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[3] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -232,7 +232,7 @@ func (x *ProposeReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ProposeReq.ProtoReflect.Descriptor instead. func (*ProposeReq) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{3} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{3} } func (x *ProposeReq) GetAddress() string { @@ -260,7 +260,7 @@ type CandidatesResp struct { func (x *CandidatesResp) Reset() { *x = CandidatesResp{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[4] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -273,7 +273,7 @@ func (x *CandidatesResp) String() string { func (*CandidatesResp) ProtoMessage() {} func (x *CandidatesResp) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[4] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -286,7 +286,7 @@ func (x *CandidatesResp) ProtoReflect() protoreflect.Message { // Deprecated: Use CandidatesResp.ProtoReflect.Descriptor instead. func (*CandidatesResp) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{4} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{4} } func (x *CandidatesResp) GetCandidates() []*Candidate { @@ -301,14 +301,15 @@ type Candidate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - Auth bool `protobuf:"varint,2,opt,name=auth,proto3" json:"auth,omitempty"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + BlsPubkey []byte `protobuf:"bytes,2,opt,name=bls_pubkey,json=blsPubkey,proto3" json:"bls_pubkey,omitempty"` + Auth bool `protobuf:"varint,3,opt,name=auth,proto3" json:"auth,omitempty"` } func (x *Candidate) Reset() { *x = Candidate{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[5] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -321,7 +322,7 @@ func (x *Candidate) String() string { func (*Candidate) ProtoMessage() {} func (x *Candidate) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[5] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -334,7 +335,7 @@ func (x *Candidate) ProtoReflect() protoreflect.Message { // Deprecated: Use Candidate.ProtoReflect.Descriptor instead. func (*Candidate) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{5} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{5} } func (x *Candidate) GetAddress() string { @@ -344,6 +345,13 @@ func (x *Candidate) GetAddress() string { return "" } +func (x *Candidate) GetBlsPubkey() []byte { + if x != nil { + return x.BlsPubkey + } + return nil +} + func (x *Candidate) GetAuth() bool { if x != nil { return x.Auth @@ -356,13 +364,15 @@ type Snapshot_Validator struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } func (x *Snapshot_Validator) Reset() { *x = Snapshot_Validator{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[6] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -375,7 +385,7 @@ func (x *Snapshot_Validator) String() string { func (*Snapshot_Validator) ProtoMessage() {} func (x *Snapshot_Validator) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[6] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -388,7 +398,14 @@ func (x *Snapshot_Validator) ProtoReflect() protoreflect.Message { // Deprecated: Use Snapshot_Validator.ProtoReflect.Descriptor instead. func (*Snapshot_Validator) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{2, 0} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *Snapshot_Validator) GetType() string { + if x != nil { + return x.Type + } + return "" } func (x *Snapshot_Validator) GetAddress() string { @@ -398,6 +415,13 @@ func (x *Snapshot_Validator) GetAddress() string { return "" } +func (x *Snapshot_Validator) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + type Snapshot_Vote struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -411,7 +435,7 @@ type Snapshot_Vote struct { func (x *Snapshot_Vote) Reset() { *x = Snapshot_Vote{} if protoimpl.UnsafeEnabled { - mi := &file_ibft_operator_proto_msgTypes[7] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -424,7 +448,7 @@ func (x *Snapshot_Vote) String() string { func (*Snapshot_Vote) ProtoMessage() {} func (x *Snapshot_Vote) ProtoReflect() protoreflect.Message { - mi := &file_ibft_operator_proto_msgTypes[7] + mi := &file_consensus_ibft_proto_ibft_operator_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -437,7 +461,7 @@ func (x *Snapshot_Vote) ProtoReflect() protoreflect.Message { // Deprecated: Use Snapshot_Vote.ProtoReflect.Descriptor instead. func (*Snapshot_Vote) Descriptor() ([]byte, []int) { - return file_ibft_operator_proto_rawDescGZIP(), []int{2, 1} + return file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP(), []int{2, 1} } func (x *Snapshot_Vote) GetValidator() string { @@ -461,80 +485,86 @@ func (x *Snapshot_Vote) GetAuth() bool { return false } -var File_ibft_operator_proto protoreflect.FileDescriptor - -var file_ibft_operator_proto_rawDesc = []byte{ - 0x0a, 0x13, 0x69, 0x62, 0x66, 0x74, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0e, 0x49, 0x62, 0x66, 0x74, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, - 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x94, 0x02, 0x0a, 0x08, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, - 0x6f, 0x72, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x6f, - 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x05, 0x76, 0x6f, - 0x74, 0x65, 0x73, 0x1a, 0x25, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x54, 0x0a, 0x04, 0x56, 0x6f, - 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, - 0x22, 0x3a, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, - 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0x3f, 0x0a, 0x0e, - 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2d, - 0x0a, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0x39, 0x0a, - 0x09, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x32, 0xde, 0x01, 0x0a, 0x0c, 0x49, 0x62, 0x66, - 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x0b, 0x47, 0x65, 0x74, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x70, 0x6f, - 0x73, 0x65, 0x12, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x38, 0x0a, 0x0a, 0x43, 0x61, 0x6e, - 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, +var File_consensus_ibft_proto_ibft_operator_proto protoreflect.FileDescriptor + +var file_consensus_ibft_proto_ibft_operator_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2f, 0x69, 0x62, 0x66, 0x74, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x62, 0x66, 0x74, 0x5f, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, 0x1a, 0x1b, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0e, 0x49, + 0x62, 0x66, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, + 0x3d, 0x0a, 0x0b, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x12, 0x16, + 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xbc, + 0x02, 0x0a, 0x08, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, + 0x27, 0x0a, 0x05, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x56, 0x6f, 0x74, + 0x65, 0x52, 0x05, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x1a, 0x4d, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x54, 0x0a, 0x04, 0x56, 0x6f, 0x74, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x75, 0x74, + 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0x3a, 0x0a, + 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0x3f, 0x0a, 0x0e, 0x43, 0x61, 0x6e, + 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x2d, 0x0a, 0x0a, 0x63, + 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0a, + 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x22, 0x58, 0x0a, 0x09, 0x43, 0x61, + 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x73, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x73, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, + 0x12, 0x12, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, + 0x61, 0x75, 0x74, 0x68, 0x32, 0xde, 0x01, 0x0a, 0x0c, 0x49, 0x62, 0x66, 0x74, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x12, 0x0f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x12, 0x30, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x0d, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x62, 0x66, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x42, 0x17, 0x5a, 0x15, 0x2f, 0x63, 0x6f, - 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2f, 0x69, 0x62, 0x66, 0x74, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x38, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x34, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x62, 0x66, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x42, 0x17, 0x5a, 0x15, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, + 0x73, 0x75, 0x73, 0x2f, 0x69, 0x62, 0x66, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_ibft_operator_proto_rawDescOnce sync.Once - file_ibft_operator_proto_rawDescData = file_ibft_operator_proto_rawDesc + file_consensus_ibft_proto_ibft_operator_proto_rawDescOnce sync.Once + file_consensus_ibft_proto_ibft_operator_proto_rawDescData = file_consensus_ibft_proto_ibft_operator_proto_rawDesc ) -func file_ibft_operator_proto_rawDescGZIP() []byte { - file_ibft_operator_proto_rawDescOnce.Do(func() { - file_ibft_operator_proto_rawDescData = protoimpl.X.CompressGZIP(file_ibft_operator_proto_rawDescData) +func file_consensus_ibft_proto_ibft_operator_proto_rawDescGZIP() []byte { + file_consensus_ibft_proto_ibft_operator_proto_rawDescOnce.Do(func() { + file_consensus_ibft_proto_ibft_operator_proto_rawDescData = protoimpl.X.CompressGZIP(file_consensus_ibft_proto_ibft_operator_proto_rawDescData) }) - return file_ibft_operator_proto_rawDescData + return file_consensus_ibft_proto_ibft_operator_proto_rawDescData } -var file_ibft_operator_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_ibft_operator_proto_goTypes = []interface{}{ +var file_consensus_ibft_proto_ibft_operator_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_consensus_ibft_proto_ibft_operator_proto_goTypes = []interface{}{ (*IbftStatusResp)(nil), // 0: v1.IbftStatusResp (*SnapshotReq)(nil), // 1: v1.SnapshotReq (*Snapshot)(nil), // 2: v1.Snapshot @@ -543,9 +573,9 @@ var file_ibft_operator_proto_goTypes = []interface{}{ (*Candidate)(nil), // 5: v1.Candidate (*Snapshot_Validator)(nil), // 6: v1.Snapshot.Validator (*Snapshot_Vote)(nil), // 7: v1.Snapshot.Vote - (*emptypb.Empty)(nil), // 8: google.protobuf.Empty + (*empty.Empty)(nil), // 8: google.protobuf.Empty } -var file_ibft_operator_proto_depIdxs = []int32{ +var file_consensus_ibft_proto_ibft_operator_proto_depIdxs = []int32{ 6, // 0: v1.Snapshot.validators:type_name -> v1.Snapshot.Validator 7, // 1: v1.Snapshot.votes:type_name -> v1.Snapshot.Vote 5, // 2: v1.CandidatesResp.candidates:type_name -> v1.Candidate @@ -564,13 +594,13 @@ var file_ibft_operator_proto_depIdxs = []int32{ 0, // [0:3] is the sub-list for field type_name } -func init() { file_ibft_operator_proto_init() } -func file_ibft_operator_proto_init() { - if File_ibft_operator_proto != nil { +func init() { file_consensus_ibft_proto_ibft_operator_proto_init() } +func file_consensus_ibft_proto_ibft_operator_proto_init() { + if File_consensus_ibft_proto_ibft_operator_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_ibft_operator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IbftStatusResp); i { case 0: return &v.state @@ -582,7 +612,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SnapshotReq); i { case 0: return &v.state @@ -594,7 +624,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Snapshot); i { case 0: return &v.state @@ -606,7 +636,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ProposeReq); i { case 0: return &v.state @@ -618,7 +648,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CandidatesResp); i { case 0: return &v.state @@ -630,7 +660,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Candidate); i { case 0: return &v.state @@ -642,7 +672,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Snapshot_Validator); i { case 0: return &v.state @@ -654,7 +684,7 @@ func file_ibft_operator_proto_init() { return nil } } - file_ibft_operator_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_consensus_ibft_proto_ibft_operator_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Snapshot_Vote); i { case 0: return &v.state @@ -671,18 +701,18 @@ func file_ibft_operator_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_ibft_operator_proto_rawDesc, + RawDescriptor: file_consensus_ibft_proto_ibft_operator_proto_rawDesc, NumEnums: 0, NumMessages: 8, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_ibft_operator_proto_goTypes, - DependencyIndexes: file_ibft_operator_proto_depIdxs, - MessageInfos: file_ibft_operator_proto_msgTypes, + GoTypes: file_consensus_ibft_proto_ibft_operator_proto_goTypes, + DependencyIndexes: file_consensus_ibft_proto_ibft_operator_proto_depIdxs, + MessageInfos: file_consensus_ibft_proto_ibft_operator_proto_msgTypes, }.Build() - File_ibft_operator_proto = out.File - file_ibft_operator_proto_rawDesc = nil - file_ibft_operator_proto_goTypes = nil - file_ibft_operator_proto_depIdxs = nil + File_consensus_ibft_proto_ibft_operator_proto = out.File + file_consensus_ibft_proto_ibft_operator_proto_rawDesc = nil + file_consensus_ibft_proto_ibft_operator_proto_goTypes = nil + file_consensus_ibft_proto_ibft_operator_proto_depIdxs = nil } diff --git a/consensus/ibft/proto/ibft_operator.proto b/consensus/ibft/proto/ibft_operator.proto index bf2aa0fc33..8c75026434 100644 --- a/consensus/ibft/proto/ibft_operator.proto +++ b/consensus/ibft/proto/ibft_operator.proto @@ -7,51 +7,54 @@ option go_package = "/consensus/ibft/proto"; import "google/protobuf/empty.proto"; service IbftOperator { - rpc GetSnapshot(SnapshotReq) returns (Snapshot); - rpc Propose(Candidate) returns (google.protobuf.Empty); - rpc Candidates(google.protobuf.Empty) returns (CandidatesResp); - rpc Status(google.protobuf.Empty) returns (IbftStatusResp); + rpc GetSnapshot(SnapshotReq) returns (Snapshot); + rpc Propose(Candidate) returns (google.protobuf.Empty); + rpc Candidates(google.protobuf.Empty) returns (CandidatesResp); + rpc Status(google.protobuf.Empty) returns (IbftStatusResp); } message IbftStatusResp { - string key = 1; + string key = 1; } message SnapshotReq { - bool latest = 1; - uint64 number = 2; + bool latest = 1; + uint64 number = 2; } message Snapshot { - repeated Validator validators = 1; + repeated Validator validators = 1; - uint64 number = 2; + uint64 number = 2; - string hash = 3; + string hash = 3; - repeated Vote votes = 4; + repeated Vote votes = 4; - message Validator { - string address = 1; - } + message Validator { + string type = 1; + string address = 2; + bytes data = 3; + } - message Vote { - string validator = 1; - string proposed = 2; - bool auth = 3; - } + message Vote { + string validator = 1; + string proposed = 2; + bool auth = 3; + } } message ProposeReq { - string address = 1; - bool auth = 2; + string address = 1; + bool auth = 2; } message CandidatesResp { - repeated Candidate candidates = 1; + repeated Candidate candidates = 1; } message Candidate { - string address = 1; - bool auth = 2; + string address = 1; + bytes bls_pubkey = 2; + bool auth = 3; } diff --git a/consensus/ibft/proto/ibft_operator_grpc.pb.go b/consensus/ibft/proto/ibft_operator_grpc.pb.go index 7a256b3603..5e0322b92c 100644 --- a/consensus/ibft/proto/ibft_operator_grpc.pb.go +++ b/consensus/ibft/proto/ibft_operator_grpc.pb.go @@ -1,13 +1,17 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.12.4 +// source: consensus/ibft/proto/ibft_operator.proto package proto import ( context "context" + empty "github.com/golang/protobuf/ptypes/empty" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - emptypb "google.golang.org/protobuf/types/known/emptypb" ) // This is a compile-time assertion to ensure that this generated file @@ -20,9 +24,9 @@ const _ = grpc.SupportPackageIsVersion7 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type IbftOperatorClient interface { GetSnapshot(ctx context.Context, in *SnapshotReq, opts ...grpc.CallOption) (*Snapshot, error) - Propose(ctx context.Context, in *Candidate, opts ...grpc.CallOption) (*emptypb.Empty, error) - Candidates(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CandidatesResp, error) - Status(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*IbftStatusResp, error) + Propose(ctx context.Context, in *Candidate, opts ...grpc.CallOption) (*empty.Empty, error) + Candidates(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*CandidatesResp, error) + Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IbftStatusResp, error) } type ibftOperatorClient struct { @@ -42,8 +46,8 @@ func (c *ibftOperatorClient) GetSnapshot(ctx context.Context, in *SnapshotReq, o return out, nil } -func (c *ibftOperatorClient) Propose(ctx context.Context, in *Candidate, opts ...grpc.CallOption) (*emptypb.Empty, error) { - out := new(emptypb.Empty) +func (c *ibftOperatorClient) Propose(ctx context.Context, in *Candidate, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) err := c.cc.Invoke(ctx, "/v1.IbftOperator/Propose", in, out, opts...) if err != nil { return nil, err @@ -51,7 +55,7 @@ func (c *ibftOperatorClient) Propose(ctx context.Context, in *Candidate, opts .. return out, nil } -func (c *ibftOperatorClient) Candidates(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CandidatesResp, error) { +func (c *ibftOperatorClient) Candidates(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*CandidatesResp, error) { out := new(CandidatesResp) err := c.cc.Invoke(ctx, "/v1.IbftOperator/Candidates", in, out, opts...) if err != nil { @@ -60,7 +64,7 @@ func (c *ibftOperatorClient) Candidates(ctx context.Context, in *emptypb.Empty, return out, nil } -func (c *ibftOperatorClient) Status(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*IbftStatusResp, error) { +func (c *ibftOperatorClient) Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IbftStatusResp, error) { out := new(IbftStatusResp) err := c.cc.Invoke(ctx, "/v1.IbftOperator/Status", in, out, opts...) if err != nil { @@ -74,9 +78,9 @@ func (c *ibftOperatorClient) Status(ctx context.Context, in *emptypb.Empty, opts // for forward compatibility type IbftOperatorServer interface { GetSnapshot(context.Context, *SnapshotReq) (*Snapshot, error) - Propose(context.Context, *Candidate) (*emptypb.Empty, error) - Candidates(context.Context, *emptypb.Empty) (*CandidatesResp, error) - Status(context.Context, *emptypb.Empty) (*IbftStatusResp, error) + Propose(context.Context, *Candidate) (*empty.Empty, error) + Candidates(context.Context, *empty.Empty) (*CandidatesResp, error) + Status(context.Context, *empty.Empty) (*IbftStatusResp, error) mustEmbedUnimplementedIbftOperatorServer() } @@ -87,13 +91,13 @@ type UnimplementedIbftOperatorServer struct { func (UnimplementedIbftOperatorServer) GetSnapshot(context.Context, *SnapshotReq) (*Snapshot, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSnapshot not implemented") } -func (UnimplementedIbftOperatorServer) Propose(context.Context, *Candidate) (*emptypb.Empty, error) { +func (UnimplementedIbftOperatorServer) Propose(context.Context, *Candidate) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Propose not implemented") } -func (UnimplementedIbftOperatorServer) Candidates(context.Context, *emptypb.Empty) (*CandidatesResp, error) { +func (UnimplementedIbftOperatorServer) Candidates(context.Context, *empty.Empty) (*CandidatesResp, error) { return nil, status.Errorf(codes.Unimplemented, "method Candidates not implemented") } -func (UnimplementedIbftOperatorServer) Status(context.Context, *emptypb.Empty) (*IbftStatusResp, error) { +func (UnimplementedIbftOperatorServer) Status(context.Context, *empty.Empty) (*IbftStatusResp, error) { return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") } func (UnimplementedIbftOperatorServer) mustEmbedUnimplementedIbftOperatorServer() {} @@ -146,7 +150,7 @@ func _IbftOperator_Propose_Handler(srv interface{}, ctx context.Context, dec fun } func _IbftOperator_Candidates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) + in := new(empty.Empty) if err := dec(in); err != nil { return nil, err } @@ -158,13 +162,13 @@ func _IbftOperator_Candidates_Handler(srv interface{}, ctx context.Context, dec FullMethod: "/v1.IbftOperator/Candidates", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IbftOperatorServer).Candidates(ctx, req.(*emptypb.Empty)) + return srv.(IbftOperatorServer).Candidates(ctx, req.(*empty.Empty)) } return interceptor(ctx, in, info, handler) } func _IbftOperator_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) + in := new(empty.Empty) if err := dec(in); err != nil { return nil, err } @@ -176,7 +180,7 @@ func _IbftOperator_Status_Handler(srv interface{}, ctx context.Context, dec func FullMethod: "/v1.IbftOperator/Status", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IbftOperatorServer).Status(ctx, req.(*emptypb.Empty)) + return srv.(IbftOperatorServer).Status(ctx, req.(*empty.Empty)) } return interceptor(ctx, in, info, handler) } @@ -206,5 +210,5 @@ var IbftOperator_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "ibft_operator.proto", + Metadata: "consensus/ibft/proto/ibft_operator.proto", } diff --git a/consensus/ibft/sign.go b/consensus/ibft/sign.go deleted file mode 100644 index 2a6a8e40e4..0000000000 --- a/consensus/ibft/sign.go +++ /dev/null @@ -1,220 +0,0 @@ -package ibft - -import ( - "crypto/ecdsa" - "fmt" - - "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/keccak" - "github.com/0xPolygon/polygon-edge/types" - "github.com/umbracle/fastrlp" -) - -const ( - // legacyCommitCode is the value that is contained in - // legacy committed seals, so it needs to be preserved in order - // for new clients to read old committed seals - legacyCommitCode = 2 -) - -func wrapCommitHash(b []byte) []byte { - return crypto.Keccak256(b, []byte{byte(legacyCommitCode)}) -} - -func ecrecoverImpl(sig, msg []byte) (types.Address, error) { - pub, err := crypto.RecoverPubkey(sig, crypto.Keccak256(msg)) - if err != nil { - return types.Address{}, err - } - - return crypto.PubKeyToAddress(pub), nil -} - -func ecrecoverProposer(h *types.Header) (types.Address, error) { - // get the extra part that contains the seal - extra, err := getIbftExtra(h) - if err != nil { - return types.Address{}, err - } - - // Calculate the header hash (keccak of RLP) - hash, err := calculateHeaderHash(h) - if err != nil { - return types.Address{}, err - } - - return ecrecoverImpl(extra.ProposerSeal, hash) -} - -func signSealImpl(prv *ecdsa.PrivateKey, h *types.Header) ([]byte, error) { - hash, err := calculateHeaderHash(h) - if err != nil { - return nil, err - } - - return crypto.Sign(prv, crypto.Keccak256(hash)) -} - -func writeProposerSeal(prv *ecdsa.PrivateKey, h *types.Header) (*types.Header, error) { - h = h.Copy() - seal, err := signSealImpl(prv, h) - - if err != nil { - return nil, err - } - - extra, err := getIbftExtra(h) - if err != nil { - return nil, err - } - - extra.ProposerSeal = seal - if err := PutIbftExtra(h, extra); err != nil { - return nil, err - } - - return h, nil -} - -// writeCommittedSeal generates the legacy committed seal using the passed in -// header hash and the private key -func writeCommittedSeal(prv *ecdsa.PrivateKey, headerHash []byte) ([]byte, error) { - return crypto.Sign( - prv, - // Of course, this keccaking of an extended array is not according to the IBFT 2.0 spec, - // but almost nothing in this legacy signing package is. This is kept - // in order to preserve the running chains that used these - // old (and very, very incorrect) signing schemes - crypto.Keccak256( - wrapCommitHash(headerHash), - ), - ) -} - -func writeCommittedSeals(h *types.Header, seals [][]byte) (*types.Header, error) { - h = h.Copy() - - if len(seals) == 0 { - return nil, fmt.Errorf("empty committed seals") - } - - for _, seal := range seals { - if len(seal) != IstanbulExtraSeal { - return nil, fmt.Errorf("invalid committed seal length") - } - } - - extra, err := getIbftExtra(h) - if err != nil { - return nil, err - } - - extra.CommittedSeal = seals - if err := PutIbftExtra(h, extra); err != nil { - return nil, err - } - - return h, nil -} - -func calculateHeaderHash(h *types.Header) ([]byte, error) { - h = h.Copy() // make a copy since we update the extra field - - arena := fastrlp.DefaultArenaPool.Get() - defer fastrlp.DefaultArenaPool.Put(arena) - - // when hashing the block for signing we have to remove from - // the extra field the seal and committed seal items - extra, err := getIbftExtra(h) - if err != nil { - return nil, err - } - - // This will effectively remove the ProposerSeal and Committed ProposerSeal fields, - // while keeping proposer vanity and validator set - // because extra.Validators is what we got from `h` in the first place. - putIbftExtraValidators(h, extra.Validators) - - vv := arena.NewArray() - vv.Set(arena.NewBytes(h.ParentHash.Bytes())) - vv.Set(arena.NewBytes(h.Sha3Uncles.Bytes())) - vv.Set(arena.NewBytes(h.Miner.Bytes())) - vv.Set(arena.NewBytes(h.StateRoot.Bytes())) - vv.Set(arena.NewBytes(h.TxRoot.Bytes())) - vv.Set(arena.NewBytes(h.ReceiptsRoot.Bytes())) - vv.Set(arena.NewBytes(h.LogsBloom[:])) - vv.Set(arena.NewUint(h.Difficulty)) - vv.Set(arena.NewUint(h.Number)) - vv.Set(arena.NewUint(h.GasLimit)) - vv.Set(arena.NewUint(h.GasUsed)) - vv.Set(arena.NewUint(h.Timestamp)) - vv.Set(arena.NewCopyBytes(h.ExtraData)) - - buf := keccak.Keccak256Rlp(nil, vv) - - return buf, nil -} - -func verifySigner(snap *Snapshot, header *types.Header) error { - signer, err := ecrecoverProposer(header) - if err != nil { - return err - } - - if !snap.Set.Includes(signer) { - return fmt.Errorf("not found signer") - } - - return nil -} - -// verifyCommittedFields is checking for consensus proof in the header -func verifyCommittedFields( - snap *Snapshot, - header *types.Header, - quorumSizeFn QuorumImplementation, -) error { - extra, err := getIbftExtra(header) - if err != nil { - return err - } - - // Committed seals shouldn't be empty - if len(extra.CommittedSeal) == 0 { - return fmt.Errorf("empty committed seals") - } - - hash, err := calculateHeaderHash(header) - if err != nil { - return err - } - - rawMsg := wrapCommitHash(hash) - - visited := map[types.Address]struct{}{} - - for _, seal := range extra.CommittedSeal { - addr, err := ecrecoverImpl(seal, rawMsg) - if err != nil { - return err - } - - if _, ok := visited[addr]; ok { - return fmt.Errorf("repeated seal") - } else { - if !snap.Set.Includes(addr) { - return fmt.Errorf("signed by non validator") - } - visited[addr] = struct{}{} - } - } - - // Valid committed seals must be at least 2F+1 - // 2F is the required number of honest validators who provided the committed seals - // +1 is the proposer - if validSeals := len(visited); validSeals < quorumSizeFn(snap.Set) { - return fmt.Errorf("not enough seals to seal block") - } - - return nil -} diff --git a/consensus/ibft/sign_test.go b/consensus/ibft/sign_test.go index d480776fd6..22e983b15d 100644 --- a/consensus/ibft/sign_test.go +++ b/consensus/ibft/sign_test.go @@ -3,6 +3,7 @@ package ibft import ( "testing" + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/types" "github.com/stretchr/testify/assert" ) @@ -10,77 +11,100 @@ import ( func TestSign_Sealer(t *testing.T) { t.Parallel() - pool := newTesterAccountPool() + pool := newTesterAccountPool(t) pool.add("A") - snap := &Snapshot{ - Set: pool.ValidatorSet(), - } + correctValset := pool.ValidatorSet() h := &types.Header{} - putIbftExtraValidators(h, pool.ValidatorSet()) + + signerA := signer.NewSigner( + signer.NewECDSAKeyManagerFromKey(pool.get("A").priv), + signer.NewECDSAKeyManagerFromKey(pool.get("A").priv), + ) + + signer.UseIstanbulHeaderHashInTest(t, signerA) + + signerA.InitIBFTExtra(h, correctValset, nil) + + h = h.ComputeHash() // non-validator address pool.add("X") - badSealedBlock, _ := writeProposerSeal(pool.get("X").priv, h) - assert.Error(t, verifySigner(snap, badSealedBlock)) + signerX := signer.NewSigner( + signer.NewECDSAKeyManagerFromKey(pool.get("X").priv), + signer.NewECDSAKeyManagerFromKey(pool.get("A").priv), + ) + + badSealedBlock, _ := signerX.WriteProposerSeal(h) + assert.Error(t, verifyProposerSeal(badSealedBlock, signerA, correctValset)) // seal the block with a validator - goodSealedBlock, _ := writeProposerSeal(pool.get("A").priv, h) - assert.NoError(t, verifySigner(snap, goodSealedBlock)) + goodSealedBlock, _ := signerA.WriteProposerSeal(h) + assert.NoError(t, verifyProposerSeal(goodSealedBlock, signerA, correctValset)) } func TestSign_CommittedSeals(t *testing.T) { t.Parallel() - pool := newTesterAccountPool() + pool := newTesterAccountPool(t) pool.add("A", "B", "C", "D", "E") - snap := &Snapshot{ - Set: pool.ValidatorSet(), - } + var ( + h = &types.Header{} + err error + ) - h := &types.Header{ - ExtraData: []byte{}, - } + correctValSet := pool.ValidatorSet() + + signerA := signer.NewSigner( + signer.NewECDSAKeyManagerFromKey(pool.get("A").priv), + signer.NewECDSAKeyManagerFromKey(pool.get("A").priv), + ) - putIbftExtraValidators(h, pool.ValidatorSet()) + signerA.InitIBFTExtra(h, correctValSet, nil) - hash, err := calculateHeaderHash(h) + h.Hash, err = signerA.CalculateHeaderHash(h) if err != nil { t.Fatalf("Unable to calculate hash, %v", err) } - h.Hash = types.BytesToHash(hash) - // non-validator address pool.add("X") - buildCommittedSeal := func(accnt []string) error { - seals := [][]byte{} + buildCommittedSeal := func(names []string) error { + seals := map[types.Address][]byte{} - for _, accnt := range accnt { - seal, err := writeCommittedSeal(pool.get(accnt).priv, h.Hash.Bytes()) + for _, name := range names { + acc := pool.get(name) + + signer := signer.NewSigner( + signer.NewECDSAKeyManagerFromKey( + acc.priv, + ), + signer.NewECDSAKeyManagerFromKey( + acc.priv, + ), + ) + + seal, err := signer.CreateCommittedSeal(h.Hash.Bytes()) assert.NoError(t, err) - seals = append(seals, seal) + seals[acc.Address()] = seal } - sealed, err := writeCommittedSeals(h, seals) + sealed, err := signerA.WriteCommittedSeals(h, seals) assert.NoError(t, err) - return verifyCommittedFields(snap, sealed, OptimalQuorumSize) + return signerA.VerifyCommittedSeals(sealed, correctValSet, OptimalQuorumSize(correctValSet)) } // Correct assert.NoError(t, buildCommittedSeal([]string{"A", "B", "C", "D"})) - // Failed - Repeated signature - assert.Error(t, buildCommittedSeal([]string{"A", "A"})) - // Failed - Non validator signature assert.Error(t, buildCommittedSeal([]string{"A", "X"})) diff --git a/consensus/ibft/signer/bls.go b/consensus/ibft/signer/bls.go new file mode 100644 index 0000000000..39cf7b07c5 --- /dev/null +++ b/consensus/ibft/signer/bls.go @@ -0,0 +1,313 @@ +package signer + +import ( + "crypto/ecdsa" + "fmt" + "math/big" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig" + "github.com/umbracle/fastrlp" +) + +// BLSKeyManager is a module that holds ECDSA and BLS keys +// and implements methods of signing by these keys +type BLSKeyManager struct { + ecdsaKey *ecdsa.PrivateKey + blsKey *bls_sig.SecretKey + address types.Address +} + +// NewBLSKeyManager initializes BLSKeyManager by the ECDSA key and BLS key which are loaded from SecretsManager +func NewBLSKeyManager(manager secrets.SecretsManager) (KeyManager, error) { + ecdsaKey, err := getOrCreateECDSAKey(manager) + if err != nil { + return nil, err + } + + blsKey, err := getOrCreateBLSKey(manager) + if err != nil { + return nil, err + } + + return NewBLSKeyManagerFromKeys(ecdsaKey, blsKey), nil +} + +// NewBLSKeyManagerFromKeys initializes BLSKeyManager from the given ECDSA and BLS keys +func NewBLSKeyManagerFromKeys(ecdsaKey *ecdsa.PrivateKey, blsKey *bls_sig.SecretKey) KeyManager { + return &BLSKeyManager{ + ecdsaKey: ecdsaKey, + blsKey: blsKey, + address: crypto.PubKeyToAddress(&ecdsaKey.PublicKey), + } +} + +// Type returns the validator type KeyManager supports +func (s *BLSKeyManager) Type() validators.ValidatorType { + return validators.BLSValidatorType +} + +// Address returns the address of KeyManager +func (s *BLSKeyManager) Address() types.Address { + return s.address +} + +// NewEmptyValidators returns empty validator collection BLSKeyManager uses +func (s *BLSKeyManager) NewEmptyValidators() validators.Validators { + return validators.NewBLSValidatorSet() +} + +// NewEmptyCommittedSeals returns empty CommittedSeals BLSKeyManager uses +func (s *BLSKeyManager) NewEmptyCommittedSeals() Seals { + return &AggregatedSeal{} +} + +func (s *BLSKeyManager) SignProposerSeal(data []byte) ([]byte, error) { + return crypto.Sign(s.ecdsaKey, data) +} + +func (s *BLSKeyManager) SignCommittedSeal(data []byte) ([]byte, error) { + return crypto.SignByBLS(s.blsKey, data) +} + +func (s *BLSKeyManager) VerifyCommittedSeal( + set validators.Validators, + addr types.Address, + rawSignature []byte, + hash []byte, +) error { + if set.Type() != s.Type() { + return ErrInvalidValidators + } + + validatorIndex := set.Index(addr) + if validatorIndex == -1 { + return ErrValidatorNotFound + } + + validator, ok := set.At(uint64(validatorIndex)).(*validators.BLSValidator) + if !ok { + return ErrInvalidValidators + } + + if err := crypto.VerifyBLSSignatureFromBytes( + validator.BLSPublicKey, + rawSignature, + hash, + ); err != nil { + return err + } + + return nil +} + +func (s *BLSKeyManager) GenerateCommittedSeals( + sealMap map[types.Address][]byte, + set validators.Validators, +) (Seals, error) { + if set.Type() != s.Type() { + return nil, ErrInvalidValidators + } + + blsSignatures, bitMap, err := getBLSSignatures(sealMap, set) + if err != nil { + return nil, err + } + + multiSignature, err := bls_sig.NewSigPop().AggregateSignatures(blsSignatures...) + if err != nil { + return nil, err + } + + multiSignatureBytes, err := multiSignature.MarshalBinary() + if err != nil { + return nil, err + } + + return &AggregatedSeal{ + Bitmap: bitMap, + Signature: multiSignatureBytes, + }, nil +} + +func (s *BLSKeyManager) VerifyCommittedSeals( + rawCommittedSeal Seals, + message []byte, + vals validators.Validators, +) (int, error) { + committedSeal, ok := rawCommittedSeal.(*AggregatedSeal) + if !ok { + return 0, ErrInvalidCommittedSealType + } + + if vals.Type() != s.Type() { + return 0, ErrInvalidValidators + } + + return verifyBLSCommittedSealsImpl(committedSeal, message, vals) +} + +func (s *BLSKeyManager) SignIBFTMessage(msg []byte) ([]byte, error) { + return crypto.Sign(s.ecdsaKey, msg) +} + +func (s *BLSKeyManager) Ecrecover(sig, digest []byte) (types.Address, error) { + return ecrecover(sig, digest) +} + +type AggregatedSeal struct { + Bitmap *big.Int + Signature []byte +} + +func (s *AggregatedSeal) Num() int { + return s.Bitmap.BitLen() +} + +func (s *AggregatedSeal) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { + x := ar.NewArray() + + if s.Bitmap == nil { + x.Set(ar.NewNull()) + } else { + x.Set(ar.NewBytes(s.Bitmap.Bytes())) + } + + if s.Signature == nil { + x.Set(ar.NewNull()) + } else { + x.Set(ar.NewCopyBytes(s.Signature)) + } + + return x +} + +func (s *AggregatedSeal) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error { + vals, err := v.GetElems() + + if err != nil { + return fmt.Errorf("mismatch of RLP type for CommittedSeal, expected list but found %s", v.Type()) + } + + if len(vals) == 0 { + return nil + } + + if len(vals) < 2 { + return fmt.Errorf("mismatch of RLP type for AggregatedCommittedSeal") + } + + var rawBitMap []byte + + rawBitMap, err = vals[0].GetBytes(rawBitMap) + if err != nil { + return err + } + + s.Bitmap = new(big.Int).SetBytes(rawBitMap) + + if s.Signature, err = vals[1].GetBytes(s.Signature); err != nil { + return err + } + + return nil +} + +func getBLSSignatures( + sealMap map[types.Address][]byte, + validators validators.Validators, +) ([]*bls_sig.Signature, *big.Int, error) { + blsSignatures := make([]*bls_sig.Signature, 0, len(sealMap)) + bitMap := new(big.Int) + + for addr, seal := range sealMap { + index := validators.Index(addr) + if index == -1 { + return nil, nil, ErrNonValidatorCommittedSeal + } + + bsig := &bls_sig.Signature{} + if err := bsig.UnmarshalBinary(seal); err != nil { + return nil, nil, err + } + + bitMap = bitMap.SetBit(bitMap, int(index), 1) + + blsSignatures = append(blsSignatures, bsig) + } + + return blsSignatures, bitMap, nil +} + +func createAggregatedBLSPubKeys( + vals validators.Validators, + bitMap *big.Int, +) (*bls_sig.MultiPublicKey, int, error) { + pubkeys := make([]*bls_sig.PublicKey, 0, vals.Len()) + + for idx := 0; idx < vals.Len(); idx++ { + if bitMap.Bit(idx) == 0 { + continue + } + + validator := vals.At(uint64(idx)) + if validator == nil { + return nil, 0, ErrValidatorNotFound + } + + blsValidator, ok := validator.(*validators.BLSValidator) + if !ok { + return nil, 0, ErrInvalidValidator + } + + pubKey, err := crypto.UnmarshalBLSPublicKey(blsValidator.BLSPublicKey) + if err != nil { + return nil, 0, err + } + + pubkeys = append(pubkeys, pubKey) + } + + key, err := bls_sig.NewSigPop().AggregatePublicKeys(pubkeys...) + if err != nil { + return nil, 0, err + } + + return key, len(pubkeys), nil +} + +func verifyBLSCommittedSealsImpl( + committedSeal *AggregatedSeal, + msg []byte, + vals validators.Validators, +) (int, error) { + if len(committedSeal.Signature) == 0 || + committedSeal.Bitmap == nil || + committedSeal.Bitmap.BitLen() == 0 { + return 0, ErrEmptyCommittedSeals + } + + aggregatedPubKey, numKeys, err := createAggregatedBLSPubKeys(vals, committedSeal.Bitmap) + if err != nil { + return 0, fmt.Errorf("failed to aggregate BLS Public Keys: %w", err) + } + + signature := &bls_sig.MultiSignature{} + if err := signature.UnmarshalBinary(committedSeal.Signature); err != nil { + return 0, err + } + + ok, err := bls_sig.NewSigPop().VerifyMultiSignature(aggregatedPubKey, msg, signature) + if err != nil { + return 0, err + } + + if !ok { + return 0, ErrInvalidSignature + } + + return numKeys, nil +} diff --git a/consensus/ibft/signer/bls_test.go b/consensus/ibft/signer/bls_test.go new file mode 100644 index 0000000000..836d2580db --- /dev/null +++ b/consensus/ibft/signer/bls_test.go @@ -0,0 +1,1073 @@ +package signer + +import ( + "crypto/ecdsa" + "errors" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/hex" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig" + "github.com/stretchr/testify/assert" +) + +func newTestBLSKeyManager(t *testing.T) (KeyManager, *ecdsa.PrivateKey, *bls_sig.SecretKey) { + t.Helper() + + testECDSAKey, _ := newTestECDSAKey(t) + testBLSKey, _ := newTestBLSKey(t) + + return NewBLSKeyManagerFromKeys(testECDSAKey, testBLSKey), testECDSAKey, testBLSKey +} + +func testAggregateBLSSignatureBytes(t *testing.T, sigs ...[]byte) []byte { + t.Helper() + + blsSignatures := make([]*bls_sig.Signature, len(sigs)) + + for idx, sigBytes := range sigs { + blsSig, err := crypto.UnmarshalBLSSignature(sigBytes) + assert.NoError(t, err) + + blsSignatures[idx] = blsSig + } + + aggregatedBLSSig, err := bls_sig.NewSigPop().AggregateSignatures(blsSignatures...) + assert.NoError(t, err) + + aggregatedBLSSigBytes, err := aggregatedBLSSig.MarshalBinary() + assert.NoError(t, err) + + return aggregatedBLSSigBytes +} + +func testBLSKeyManagerToBLSValidator(t *testing.T, keyManager KeyManager) *validators.BLSValidator { + t.Helper() + + blsKeyManager, ok := keyManager.(*BLSKeyManager) + assert.True(t, ok) + + pubkeyBytes, err := crypto.BLSSecretKeyToPubkeyBytes(blsKeyManager.blsKey) + assert.NoError(t, err) + + return validators.NewBLSValidator( + blsKeyManager.Address(), + pubkeyBytes, + ) +} + +func testCreateAggregatedSignature(t *testing.T, msg []byte, keyManagers ...KeyManager) []byte { + t.Helper() + + signatures := make([][]byte, len(keyManagers)) + + for idx, km := range keyManagers { + sig, err := km.SignCommittedSeal(msg) + assert.NoError(t, err) + + signatures[idx] = sig + } + + return testAggregateBLSSignatureBytes(t, signatures...) +} + +// assert equality of marshalled aggregated BLS Public Keys +// because the field values in MultiPublicKey may be different for the same keys +func assertEqualAggregatedBLSPublicKeys(t *testing.T, apk1, apk2 *bls_sig.MultiPublicKey) { + t.Helper() + + apkBytes1, err := apk1.MarshalBinary() + assert.NoError(t, err) + + apkBytes2, err := apk2.MarshalBinary() + assert.NoError(t, err) + + assert.Equal(t, apkBytes1, apkBytes2) +} + +func TestNewBLSKeyManager(t *testing.T) { + t.Parallel() + + testECDSAKey, testECDSAKeyEncoded := newTestECDSAKey(t) + testBLSKey, testBLSKeyEncoded := newTestBLSKey(t) + + testSecretName := func(name string) { + t.Helper() + + // make sure that the correct key is given + assert.Contains( + t, + []string{secrets.ValidatorKey, secrets.ValidatorBLSKey}, + name, + ) + } + + //lint:ignore dupl + tests := []struct { + name string + mockSecretManager *MockSecretManager + expectedResult KeyManager + expectedErr error + }{ + { + name: "should initialize BLSKeyManager from the loaded ECDSA and BLS key", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + switch name { + case secrets.ValidatorKey: + return testECDSAKeyEncoded, nil + case secrets.ValidatorBLSKey: + return testBLSKeyEncoded, nil + } + + return nil, nil + }, + }, + expectedResult: &BLSKeyManager{ + ecdsaKey: testECDSAKey, + blsKey: testBLSKey, + address: crypto.PubKeyToAddress(&testECDSAKey.PublicKey), + }, + expectedErr: nil, + }, + { + name: "should return error if getOrCreateECDSAKey returns error", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + switch name { + case secrets.ValidatorKey: + // return error instead of key + return nil, errTest + case secrets.ValidatorBLSKey: + return testBLSKeyEncoded, nil + } + + return nil, nil + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + { + name: "should return error if getOrCreateBLSKey returns error", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + switch name { + case secrets.ValidatorKey: + return testECDSAKeyEncoded, nil + case secrets.ValidatorBLSKey: + // return error instead of key + return nil, errTest + } + + return nil, nil + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := NewBLSKeyManager(test.mockSecretManager) + + assert.Equal(t, test.expectedResult, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +func TestNewECDSAKeyManagerFromKeys(t *testing.T) { + t.Parallel() + + testKey, _ := newTestECDSAKey(t) + testBLSKey, _ := newTestBLSKey(t) + + assert.Equal( + t, + &BLSKeyManager{ + ecdsaKey: testKey, + blsKey: testBLSKey, + address: crypto.PubKeyToAddress(&testKey.PublicKey), + }, + NewBLSKeyManagerFromKeys(testKey, testBLSKey), + ) +} + +func TestBLSKeyManagerType(t *testing.T) { + t.Parallel() + + blsKeyManager, _, _ := newTestBLSKeyManager(t) + + assert.Equal( + t, + validators.BLSValidatorType, + blsKeyManager.Type(), + ) +} + +func TestBLSKeyManagerAddress(t *testing.T) { + t.Parallel() + + ecdsaKey, _ := newTestECDSAKey(t) + blsKey, _ := newTestBLSKey(t) + blsKeyManager := NewBLSKeyManagerFromKeys(ecdsaKey, blsKey) + + assert.Equal( + t, + crypto.PubKeyToAddress(&ecdsaKey.PublicKey), + blsKeyManager.Address(), + ) +} + +func TestBLSKeyManagerNewEmptyValidators(t *testing.T) { + t.Parallel() + + blsKeyManager, _, _ := newTestBLSKeyManager(t) + + assert.Equal( + t, + validators.NewBLSValidatorSet(), + blsKeyManager.NewEmptyValidators(), + ) +} + +func TestBLSKeyManagerNewEmptyCommittedSeals(t *testing.T) { + t.Parallel() + + blsKeyManager, _, _ := newTestBLSKeyManager(t) + + assert.Equal( + t, + &AggregatedSeal{}, + blsKeyManager.NewEmptyCommittedSeals(), + ) +} + +func TestBLSKeyManagerSignProposerSeal(t *testing.T) { + t.Parallel() + + blsKeyManager, _, _ := newTestBLSKeyManager(t) + msg := crypto.Keccak256( + hex.MustDecodeHex(testHeaderHashHex), + ) + + proposerSeal, err := blsKeyManager.SignProposerSeal(msg) + assert.NoError(t, err) + + recoveredAddress, err := ecrecover(proposerSeal, msg) + assert.NoError(t, err) + + assert.Equal( + t, + blsKeyManager.Address(), + recoveredAddress, + ) +} + +func TestBLSKeyManagerSignCommittedSeal(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _, blsKey := newTestBLSKeyManager(t) + blsPubKey, err := blsKey.GetPublicKey() + assert.NoError(t, err) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + proposerSealBytes, err := ecdsaKeyManager.SignCommittedSeal(msg) + assert.NoError(t, err) + + proposerSeal, err := crypto.UnmarshalBLSSignature(proposerSealBytes) + assert.NoError(t, err) + + assert.NoError( + t, + crypto.VerifyBLSSignature( + blsPubKey, + proposerSeal, + msg, + ), + ) +} + +func TestBLSKeyManagerVerifyCommittedSeal(t *testing.T) { + t.Parallel() + + blsKeyManager1, _, blsSecretKey1 := newTestBLSKeyManager(t) + blsKeyManager2, _, _ := newTestBLSKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctSignature, err := blsKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + wrongSignature, err := blsKeyManager2.SignCommittedSeal(msg) + assert.NoError(t, err) + + blsPublicKey1, err := blsSecretKey1.GetPublicKey() + assert.NoError(t, err) + + blsPublicKeyBytes, err := blsPublicKey1.MarshalBinary() + assert.NoError(t, err) + + tests := []struct { + name string + validators validators.Validators + address types.Address + signature []byte + message []byte + expectedErr error + }{ + { + name: "should return ErrInvalidValidators if validators is wrong type", + validators: validators.NewECDSAValidatorSet(), + address: blsKeyManager1.Address(), + signature: []byte{}, + message: []byte{}, + expectedErr: ErrInvalidValidators, + }, + { + name: "should return ErrInvalidSignature if the address is not in the validators", + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, blsKeyManager2), + ), + address: blsKeyManager1.Address(), + signature: []byte{}, + message: []byte{}, + expectedErr: ErrValidatorNotFound, + }, + { + name: "should return crypto.ErrInvalidBLSSignature if it's wrong signature", + validators: validators.NewBLSValidatorSet( + validators.NewBLSValidator( + blsKeyManager1.Address(), + blsPublicKeyBytes, + ), + ), + address: blsKeyManager1.Address(), + signature: wrongSignature, + message: msg, + expectedErr: crypto.ErrInvalidBLSSignature, + }, + { + name: "should return nil if it's correct signature", + validators: validators.NewBLSValidatorSet( + validators.NewBLSValidator( + blsKeyManager1.Address(), + blsPublicKeyBytes, + ), + ), + address: blsKeyManager1.Address(), + signature: correctSignature, + message: msg, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + test.expectedErr, + blsKeyManager1.VerifyCommittedSeal( + test.validators, + test.address, + test.signature, + test.message, + ), + ) + }) + } +} + +func TestBLSKeyManagerGenerateCommittedSeals(t *testing.T) { + t.Parallel() + + blsKeyManager1, _, _ := newTestBLSKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctCommittedSeal, err := blsKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + aggregatedBLSSigBytes := testCreateAggregatedSignature( + t, + msg, + blsKeyManager1, + ) + + tests := []struct { + name string + sealMap map[types.Address][]byte + validators validators.Validators + expectedRes Seals + expectedErr error + }{ + { + name: "should return ErrInvalidValidators if rawValidators is not *BLSValidators", + sealMap: nil, + validators: validators.NewECDSAValidatorSet(), + expectedRes: nil, + expectedErr: ErrInvalidValidators, + }, + { + name: "should return error if getBLSSignatures returns error", + sealMap: map[types.Address][]byte{ + blsKeyManager1.Address(): correctCommittedSeal, + }, + validators: validators.NewBLSValidatorSet(), + expectedRes: nil, + expectedErr: ErrNonValidatorCommittedSeal, + }, + { + name: "should return error if sealMap is empty", + sealMap: map[types.Address][]byte{}, + validators: validators.NewBLSValidatorSet(), + expectedRes: nil, + expectedErr: errors.New("at least one signature is required"), + }, + { + name: "should return AggregatedSeal if it's successful", + sealMap: map[types.Address][]byte{ + blsKeyManager1.Address(): correctCommittedSeal, + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator( + t, + blsKeyManager1, + ), + ), + expectedRes: &AggregatedSeal{ + Bitmap: big.NewInt(0).SetBit(new(big.Int), 0, 1), + Signature: aggregatedBLSSigBytes, + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := blsKeyManager1.GenerateCommittedSeals( + test.sealMap, + test.validators, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} + +func TestBLSKeyManagerVerifyCommittedSeals(t *testing.T) { + t.Parallel() + + blsKeyManager1, _, _ := newTestBLSKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + aggregatedBLSSigBytes := testCreateAggregatedSignature( + t, + msg, + blsKeyManager1, + ) + + tests := []struct { + name string + rawCommittedSeals Seals + hash []byte + validators validators.Validators + expectedRes int + expectedErr error + }{ + { + name: "should return ErrInvalidCommittedSealType if rawCommittedSeal is not *AggregatedSeal", + rawCommittedSeals: &SerializedSeal{}, + hash: nil, + validators: nil, + expectedRes: 0, + expectedErr: ErrInvalidCommittedSealType, + }, + { + name: "should return ErrInvalidValidators if rawValidators is not *BLSValidators", + rawCommittedSeals: &AggregatedSeal{ + Bitmap: big.NewInt(0).SetBit(new(big.Int), 0, 1), + Signature: aggregatedBLSSigBytes, + }, + validators: validators.NewECDSAValidatorSet(), + expectedRes: 0, + expectedErr: ErrInvalidValidators, + }, + { + name: "should return size of AggregatedSeal if it's successful", + rawCommittedSeals: &AggregatedSeal{ + Bitmap: big.NewInt(0).SetBit(new(big.Int), 0, 1), + Signature: aggregatedBLSSigBytes, + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator( + t, + blsKeyManager1, + ), + ), + expectedRes: 1, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := blsKeyManager1.VerifyCommittedSeals( + test.rawCommittedSeals, + msg, + test.validators, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} + +func TestBLSKeyManagerSignIBFTMessageAndEcrecover(t *testing.T) { + t.Parallel() + + blsKeyManager, _, _ := newTestBLSKeyManager(t) + msg := crypto.Keccak256([]byte("message")) + + proposerSeal, err := blsKeyManager.SignIBFTMessage(msg) + assert.NoError(t, err) + + recoveredAddress, err := blsKeyManager.Ecrecover(proposerSeal, msg) + assert.NoError(t, err) + + assert.Equal( + t, + blsKeyManager.Address(), + recoveredAddress, + ) +} + +func Test_getBLSSignatures(t *testing.T) { + t.Parallel() + + validatorKeyManager, _, _ := newTestBLSKeyManager(t) + nonValidatorKeyManager, _, _ := newTestBLSKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + validatorCommittedSeal, err := validatorKeyManager.SignCommittedSeal(msg) + assert.NoError(t, err) + + nonValidatorCommittedSeal, err := nonValidatorKeyManager.SignCommittedSeal(msg) + assert.NoError(t, err) + + wrongCommittedSeal := []byte("fake committed seal") + + validatorSignature, err := crypto.UnmarshalBLSSignature(validatorCommittedSeal) + assert.NoError(t, err) + + tests := []struct { + name string + sealMap map[types.Address][]byte + validators validators.Validators + expectedSignatures []*bls_sig.Signature + expectedBitMap *big.Int + expectedErr error + }{ + { + name: "should return ErrNonValidatorCommittedSeal if sealMap has committed seal signed by non validator", + sealMap: map[types.Address][]byte{ + nonValidatorKeyManager.Address(): nonValidatorCommittedSeal, + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator( + t, + validatorKeyManager, + ), + ), + expectedSignatures: nil, + expectedBitMap: nil, + expectedErr: ErrNonValidatorCommittedSeal, + }, + { + name: "should return error if unmarshalling committed seal is failed", + sealMap: map[types.Address][]byte{ + validatorKeyManager.Address(): wrongCommittedSeal, + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator( + t, + validatorKeyManager, + ), + ), + expectedSignatures: nil, + expectedBitMap: nil, + expectedErr: errors.New("signature must be 96 bytes"), + }, + { + name: "should return signatures and bitmap if all committed seals are right and signed by validators", + sealMap: map[types.Address][]byte{ + validatorKeyManager.Address(): validatorCommittedSeal, + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator( + t, + validatorKeyManager, + ), + ), + expectedSignatures: []*bls_sig.Signature{ + validatorSignature, + }, + expectedBitMap: new(big.Int).SetBit(new(big.Int), 0, 1), + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + sigs, bitmap, err := getBLSSignatures( + test.sealMap, + test.validators, + ) + + assert.ElementsMatch( + t, + test.expectedSignatures, + sigs, + ) + assert.Equal(t, test.expectedBitMap, bitmap) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } + + t.Run("multiple committed seals by validators", func(t *testing.T) { + t.Parallel() + + // which validator signed committed seals + signerFlags := []bool{ + false, + true, + false, + true, + true, + } + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + sealMap := make(map[types.Address][]byte) + validators := validators.NewBLSValidatorSet() + + expectedSignatures := make([]*bls_sig.Signature, 0, len(signerFlags)) + expectedBitMap := new(big.Int) + + for idx, signed := range signerFlags { + blsKeyManager, _, _ := newTestBLSKeyManager(t) + + // add to validators + assert.NoError( + t, + validators.Add( + testBLSKeyManagerToBLSValidator( + t, + blsKeyManager, + ), + ), + ) + + if !signed { + continue + } + + committedSeal, err := blsKeyManager.SignCommittedSeal(msg) + assert.NoError(t, err) + + // set committed seals to sealMap + sealMap[blsKeyManager.Address()] = committedSeal + + // build expected signatures + signature, err := crypto.UnmarshalBLSSignature(committedSeal) + assert.NoError(t, err) + + expectedSignatures = append(expectedSignatures, signature) + + // build expected bit map + expectedBitMap = expectedBitMap.SetBit(expectedBitMap, idx, 1) + } + + signatures, bitmap, err := getBLSSignatures( + sealMap, + validators, + ) + + // the order might be different due to scanning sealMap + assert.ElementsMatch( + t, + expectedSignatures, + signatures, + ) + assert.Equal(t, expectedBitMap, bitmap) + assert.NoError(t, err) + }) +} + +func Test_createAggregatedBLSPubKeys(t *testing.T) { + t.Parallel() + + t.Run("multiple validators", func(t *testing.T) { + t.Parallel() + + // which validator signed committed seals + signerFlags := []bool{ + false, + true, + false, + true, + true, + } + + validators := validators.NewBLSValidatorSet() + bitMap := new(big.Int) + + expectedBLSPublicKeys := []*bls_sig.PublicKey{} + expectedNumSigners := 0 + + for idx, signed := range signerFlags { + blsKeyManager, _, blsSecretKey := newTestBLSKeyManager(t) + + // add to validators + assert.NoError( + t, + validators.Add( + testBLSKeyManagerToBLSValidator( + t, + blsKeyManager, + ), + ), + ) + + if !signed { + continue + } + + // set bit in bitmap + bitMap = bitMap.SetBit(bitMap, idx, 1) + + blsPubKey, err := blsSecretKey.GetPublicKey() + assert.NoError(t, err) + + expectedBLSPublicKeys = append(expectedBLSPublicKeys, blsPubKey) + expectedNumSigners++ + } + + expectedAggregatedBLSPublicKeys, err := bls_sig.NewSigPop().AggregatePublicKeys( + expectedBLSPublicKeys..., + ) + assert.NoError(t, err) + + aggregatedPubKey, num, err := createAggregatedBLSPubKeys( + validators, + bitMap, + ) + + assert.NoError(t, err) + assert.Equal(t, expectedNumSigners, num) + + assertEqualAggregatedBLSPublicKeys(t, expectedAggregatedBLSPublicKeys, aggregatedPubKey) + }) + + t.Run("should return error if bitMap is empty", func(t *testing.T) { + t.Parallel() + + aggrecatedPubKeys, num, err := createAggregatedBLSPubKeys( + validators.NewBLSValidatorSet(), + new(big.Int), + ) + + assert.Nil(t, aggrecatedPubKeys) + assert.Zero(t, num) + assert.ErrorContains(t, err, "at least one public key is required") + }) + + t.Run("should return error if public key is wrong", func(t *testing.T) { + t.Parallel() + + aggrecatedPubKeys, num, err := createAggregatedBLSPubKeys( + validators.NewBLSValidatorSet( + validators.NewBLSValidator( + types.StringToAddress("0"), + []byte("fake"), + ), + ), + new(big.Int).SetBit(new(big.Int), 0, 1), + ) + + assert.Nil(t, aggrecatedPubKeys) + assert.Zero(t, num) + assert.ErrorContains(t, err, "public key must be 48 bytes") + }) +} + +func Test_verifyBLSCommittedSealsImpl(t *testing.T) { + t.Parallel() + + validatorKeyManager1, _, _ := newTestBLSKeyManager(t) + validatorKeyManager2, _, _ := newTestBLSKeyManager(t) + validatorKeyManager3, _, _ := newTestBLSKeyManager(t) + validatorKeyManager4, _, _ := newTestBLSKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctAggregatedSig := testCreateAggregatedSignature( + t, + msg, + validatorKeyManager1, + validatorKeyManager2, + ) + + wrongAggregatedSig := testCreateAggregatedSignature( + t, + []byte("fake"), + validatorKeyManager1, + validatorKeyManager2, + ) + + tests := []struct { + name string + committedSeal *AggregatedSeal + msg []byte + validators validators.Validators + expectedRes int + expectedErr error + }{ + { + name: "should return ErrEmptyCommittedSeals if committedSeal.Signature is empty", + committedSeal: &AggregatedSeal{ + Signature: []byte{}, + Bitmap: new(big.Int).SetBit(new(big.Int), 0, 1), + }, + expectedRes: 0, + expectedErr: ErrEmptyCommittedSeals, + }, + { + name: "should return ErrEmptyCommittedSeals if committedSeal.BitMap is nil", + committedSeal: &AggregatedSeal{ + Signature: []byte("test"), + Bitmap: nil, + }, + expectedRes: 0, + expectedErr: ErrEmptyCommittedSeals, + }, + { + name: "should return ErrEmptyCommittedSeals if committedSeal.BitMap is zero", + committedSeal: &AggregatedSeal{ + Signature: []byte("test"), + Bitmap: new(big.Int), + }, + expectedRes: 0, + expectedErr: ErrEmptyCommittedSeals, + }, + { + name: "should return error if failed to aggregate public keys", + committedSeal: &AggregatedSeal{ + Signature: []byte("test"), + Bitmap: new(big.Int).SetBit(new(big.Int), 0, 1), + }, + validators: validators.NewBLSValidatorSet( + &validators.BLSValidator{ + BLSPublicKey: []byte("test"), + }, + ), + expectedRes: 0, + expectedErr: errors.New("failed to aggregate BLS Public Keys: public key must be 48 bytes"), + }, + { + name: "should return error if failed to unmarshal aggregated signature", + committedSeal: &AggregatedSeal{ + Signature: []byte("test"), + Bitmap: new(big.Int).SetBit(new(big.Int), 0, 1), + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager2), + ), + expectedRes: 0, + expectedErr: errors.New("multi signature must be 96 bytes"), + }, + { + name: "should return error if message is nil", + committedSeal: &AggregatedSeal{ + Signature: correctAggregatedSig, + Bitmap: new(big.Int).SetBit(new(big.Int), 0, 1), + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager2), + ), + msg: nil, + expectedRes: 0, + expectedErr: errors.New("signature and message and public key cannot be nil or zero"), + }, + { + name: "should return ErrInvalidSignature if verification failed (different message)", + committedSeal: &AggregatedSeal{ + Signature: wrongAggregatedSig, + Bitmap: new(big.Int).SetBytes([]byte{0x3}), // validator1 & validator2 + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager2), + ), + msg: msg, + expectedRes: 0, + expectedErr: ErrInvalidSignature, + }, + { + name: "should return ErrInvalidSignature if verification failed (wrong validator set)", + committedSeal: &AggregatedSeal{ + Signature: correctAggregatedSig, + Bitmap: new(big.Int).SetBytes([]byte{0x3}), // validator1 & validator 2 + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager3), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager4), + ), + msg: msg, + expectedRes: 0, + expectedErr: ErrInvalidSignature, + }, + { + name: "should return ErrInvalidSignature if verification failed (smaller validator set)", + committedSeal: &AggregatedSeal{ + Signature: correctAggregatedSig, + Bitmap: new(big.Int).SetBytes([]byte{0x1}), // validator1 + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + ), + msg: msg, + expectedRes: 0, + expectedErr: ErrInvalidSignature, + }, + { + name: "should return ErrInvalidSignature if verification failed (bigger validator set)", + committedSeal: &AggregatedSeal{ + Signature: correctAggregatedSig, + Bitmap: new(big.Int).SetBytes([]byte{0x7}), // validator1 & validator 2 & validator 3 + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager2), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager3), + ), + msg: msg, + expectedRes: 0, + expectedErr: ErrInvalidSignature, + }, + { + name: "should succeed", + committedSeal: &AggregatedSeal{ + Signature: correctAggregatedSig, + Bitmap: new(big.Int).SetBytes([]byte{0x3}), // validator1 & validator 2 + }, + validators: validators.NewBLSValidatorSet( + testBLSKeyManagerToBLSValidator(t, validatorKeyManager1), + testBLSKeyManagerToBLSValidator(t, validatorKeyManager2), + ), + msg: msg, + expectedRes: 2, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := verifyBLSCommittedSealsImpl( + test.committedSeal, + test.msg, + test.validators, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} diff --git a/consensus/ibft/signer/ecdsa.go b/consensus/ibft/signer/ecdsa.go new file mode 100644 index 0000000000..4e7377ed7b --- /dev/null +++ b/consensus/ibft/signer/ecdsa.go @@ -0,0 +1,211 @@ +package signer + +import ( + "crypto/ecdsa" + "fmt" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/umbracle/fastrlp" +) + +// ECDSAKeyManager is a module that holds ECDSA key +// and implements methods of signing by this key +type ECDSAKeyManager struct { + key *ecdsa.PrivateKey + address types.Address +} + +// NewECDSAKeyManager initializes ECDSAKeyManager by the ECDSA key loaded from SecretsManager +func NewECDSAKeyManager(manager secrets.SecretsManager) (KeyManager, error) { + key, err := getOrCreateECDSAKey(manager) + if err != nil { + return nil, err + } + + return NewECDSAKeyManagerFromKey(key), nil +} + +// NewECDSAKeyManagerFromKey initializes ECDSAKeyManager from the given ECDSA key +func NewECDSAKeyManagerFromKey(key *ecdsa.PrivateKey) KeyManager { + return &ECDSAKeyManager{ + key: key, + address: crypto.PubKeyToAddress(&key.PublicKey), + } +} + +// Type returns the validator type KeyManager supports +func (s *ECDSAKeyManager) Type() validators.ValidatorType { + return validators.ECDSAValidatorType +} + +// Address returns the address of KeyManager +func (s *ECDSAKeyManager) Address() types.Address { + return s.address +} + +// NewEmptyValidators returns empty validator collection ECDSAKeyManager uses +func (s *ECDSAKeyManager) NewEmptyValidators() validators.Validators { + return validators.NewECDSAValidatorSet() +} + +// NewEmptyCommittedSeals returns empty CommittedSeals ECDSAKeyManager uses +func (s *ECDSAKeyManager) NewEmptyCommittedSeals() Seals { + return &SerializedSeal{} +} + +// SignProposerSeal signs the given message by ECDSA key the ECDSAKeyManager holds for ProposerSeal +func (s *ECDSAKeyManager) SignProposerSeal(message []byte) ([]byte, error) { + return crypto.Sign(s.key, message) +} + +// SignProposerSeal signs the given message by ECDSA key the ECDSAKeyManager holds for committed seal +func (s *ECDSAKeyManager) SignCommittedSeal(message []byte) ([]byte, error) { + return crypto.Sign(s.key, message) +} + +// VerifyCommittedSeal verifies a committed seal +func (s *ECDSAKeyManager) VerifyCommittedSeal( + vals validators.Validators, + address types.Address, + signature []byte, + message []byte, +) error { + if vals.Type() != s.Type() { + return ErrInvalidValidators + } + + signer, err := s.Ecrecover(signature, message) + if err != nil { + return ErrInvalidSignature + } + + if address != signer { + return ErrSignerMismatch + } + + if !vals.Includes(address) { + return ErrNonValidatorCommittedSeal + } + + return nil +} + +func (s *ECDSAKeyManager) GenerateCommittedSeals( + sealMap map[types.Address][]byte, + _ validators.Validators, +) (Seals, error) { + seals := [][]byte{} + + for _, seal := range sealMap { + if len(seal) != IstanbulExtraSeal { + return nil, ErrInvalidCommittedSealLength + } + + seals = append(seals, seal) + } + + serializedSeal := SerializedSeal(seals) + + return &serializedSeal, nil +} + +func (s *ECDSAKeyManager) VerifyCommittedSeals( + rawCommittedSeal Seals, + digest []byte, + vals validators.Validators, +) (int, error) { + committedSeal, ok := rawCommittedSeal.(*SerializedSeal) + if !ok { + return 0, ErrInvalidCommittedSealType + } + + if vals.Type() != s.Type() { + return 0, ErrInvalidValidators + } + + return s.verifyCommittedSealsImpl(committedSeal, digest, vals) +} + +func (s *ECDSAKeyManager) SignIBFTMessage(msg []byte) ([]byte, error) { + return crypto.Sign(s.key, msg) +} + +func (s *ECDSAKeyManager) Ecrecover(sig, digest []byte) (types.Address, error) { + return ecrecover(sig, digest) +} + +func (s *ECDSAKeyManager) verifyCommittedSealsImpl( + committedSeal *SerializedSeal, + msg []byte, + validators validators.Validators, +) (int, error) { + numSeals := committedSeal.Num() + if numSeals == 0 { + return 0, ErrEmptyCommittedSeals + } + + visited := make(map[types.Address]bool) + + for _, seal := range *committedSeal { + addr, err := s.Ecrecover(seal, msg) + if err != nil { + return 0, err + } + + if visited[addr] { + return 0, ErrRepeatedCommittedSeal + } + + if !validators.Includes(addr) { + return 0, ErrNonValidatorCommittedSeal + } + + visited[addr] = true + } + + return numSeals, nil +} + +type SerializedSeal [][]byte + +func (s *SerializedSeal) Num() int { + return len(*s) +} + +func (s *SerializedSeal) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { + if len(*s) == 0 { + return ar.NewNullArray() + } + + committed := ar.NewArray() + + for _, a := range *s { + if len(a) == 0 { + committed.Set(ar.NewNull()) + } else { + committed.Set(ar.NewCopyBytes(a)) + } + } + + return committed +} + +func (s *SerializedSeal) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error { + vals, err := v.GetElems() + if err != nil { + return fmt.Errorf("mismatch of RLP type for CommittedSeal, expected list but found %s", v.Type()) + } + + (*s) = make([][]byte, len(vals)) + + for indx, val := range vals { + if (*s)[indx], err = val.GetBytes((*s)[indx]); err != nil { + return err + } + } + + return nil +} diff --git a/consensus/ibft/signer/ecdsa_test.go b/consensus/ibft/signer/ecdsa_test.go new file mode 100644 index 0000000000..6468fdfc7f --- /dev/null +++ b/consensus/ibft/signer/ecdsa_test.go @@ -0,0 +1,554 @@ +package signer + +import ( + "crypto/ecdsa" + "errors" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/hex" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +func newTestECDSAKeyManager(t *testing.T) (KeyManager, *ecdsa.PrivateKey) { + t.Helper() + + testKey, _ := newTestECDSAKey(t) + + return NewECDSAKeyManagerFromKey(testKey), testKey +} + +func TestNewECDSAKeyManager(t *testing.T) { + t.Parallel() + + testKey, testKeyEncoded := newTestECDSAKey(t) + + testSecretName := func(name string) { + t.Helper() + + // make sure that the correct key is given + assert.Equal(t, secrets.ValidatorKey, name) + } + + //lint:ignore dupl + tests := []struct { + name string + mockSecretManager *MockSecretManager + expectedResult KeyManager + expectedErr error + }{ + { + name: "should initialize ECDSAKeyManager from the loaded ECDSA key", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return testKeyEncoded, nil + }, + }, + expectedResult: &ECDSAKeyManager{ + key: testKey, + address: crypto.PubKeyToAddress(&testKey.PublicKey), + }, + expectedErr: nil, + }, + { + name: "should return error if getOrCreateECDSAKey returns error", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return nil, errTest + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := NewECDSAKeyManager(test.mockSecretManager) + + assert.Equal(t, test.expectedResult, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} +func TestNewECDSAKeyManagerFromKey(t *testing.T) { + t.Parallel() + + testKey, _ := newTestECDSAKey(t) + + assert.Equal( + t, + &ECDSAKeyManager{ + key: testKey, + address: crypto.PubKeyToAddress(&testKey.PublicKey), + }, + NewECDSAKeyManagerFromKey(testKey), + ) +} + +func TestECDSAKeyManagerType(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + + assert.Equal( + t, + validators.ECDSAValidatorType, + ecdsaKeyManager.Type(), + ) +} + +func TestECDSAKeyManagerAddress(t *testing.T) { + t.Parallel() + + ecdsaKey, _ := newTestECDSAKey(t) + ecdsaKeyManager := NewECDSAKeyManagerFromKey(ecdsaKey) + + assert.Equal( + t, + crypto.PubKeyToAddress(&ecdsaKey.PublicKey), + ecdsaKeyManager.Address(), + ) +} + +func TestECDSAKeyManagerNewEmptyValidators(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + + assert.Equal( + t, + validators.NewECDSAValidatorSet(), + ecdsaKeyManager.NewEmptyValidators(), + ) +} + +func TestECDSAKeyManagerNewEmptyCommittedSeals(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + + assert.Equal( + t, + &SerializedSeal{}, + ecdsaKeyManager.NewEmptyCommittedSeals(), + ) +} + +func TestECDSAKeyManagerSignProposerSeal(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + msg := crypto.Keccak256( + hex.MustDecodeHex(testHeaderHashHex), + ) + + proposerSeal, err := ecdsaKeyManager.SignProposerSeal(msg) + assert.NoError(t, err) + + recoveredAddress, err := ecrecover(proposerSeal, msg) + assert.NoError(t, err) + + assert.Equal( + t, + ecdsaKeyManager.Address(), + recoveredAddress, + ) +} + +func TestECDSAKeyManagerSignCommittedSeal(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + proposerSeal, err := ecdsaKeyManager.SignCommittedSeal(msg) + assert.NoError(t, err) + + recoveredAddress, err := ecrecover(proposerSeal, msg) + assert.NoError(t, err) + + assert.Equal( + t, + ecdsaKeyManager.Address(), + recoveredAddress, + ) +} + +func TestECDSAKeyManagerVerifyCommittedSeal(t *testing.T) { + t.Parallel() + + ecdsaKeyManager1, _ := newTestECDSAKeyManager(t) + ecdsaKeyManager2, _ := newTestECDSAKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctSignature, err := ecdsaKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + wrongSignature, err := ecdsaKeyManager2.SignCommittedSeal(msg) + assert.NoError(t, err) + + tests := []struct { + name string + validators validators.Validators + address types.Address + signature []byte + message []byte + expectedErr error + }{ + { + name: "should return ErrInvalidValidators if validators is wrong type", + validators: validators.NewBLSValidatorSet(), + address: ecdsaKeyManager1.Address(), + signature: []byte{}, + message: []byte{}, + expectedErr: ErrInvalidValidators, + }, + { + name: "should return ErrInvalidSignature if ecrecover failed", + validators: validators.NewECDSAValidatorSet(), + address: ecdsaKeyManager1.Address(), + signature: []byte{}, + message: []byte{}, + expectedErr: ErrInvalidSignature, + }, + { + name: "should return ErrSignerMismatch if the signature is signed by different signer", + validators: validators.NewECDSAValidatorSet(), + address: ecdsaKeyManager1.Address(), + signature: wrongSignature, + message: msg, + expectedErr: ErrSignerMismatch, + }, + { + name: "should return ErrNonValidatorCommittedSeal if the signer is not in the validators", + validators: validators.NewECDSAValidatorSet(), + address: ecdsaKeyManager1.Address(), + signature: correctSignature, + message: msg, + expectedErr: ErrNonValidatorCommittedSeal, + }, + { + name: "should return nil if it's verified", + validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + ecdsaKeyManager1.Address(), + ), + ), + address: ecdsaKeyManager1.Address(), + signature: correctSignature, + message: msg, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + test.expectedErr, + ecdsaKeyManager1.VerifyCommittedSeal( + test.validators, + test.address, + test.signature, + test.message, + ), + ) + }) + } +} + +func TestECDSAKeyManagerGenerateCommittedSeals(t *testing.T) { + t.Parallel() + + ecdsaKeyManager1, _ := newTestECDSAKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctCommittedSeal, err := ecdsaKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + wrongCommittedSeal := []byte("fake") + + tests := []struct { + name string + sealMap map[types.Address][]byte + expectedRes Seals + expectedErr error + }{ + { + name: "should return ErrInvalidCommittedSealLength if the size of committed seal doesn't equal to IstanbulExtraSeal", + sealMap: map[types.Address][]byte{ + ecdsaKeyManager1.Address(): wrongCommittedSeal, + }, + expectedRes: nil, + expectedErr: ErrInvalidCommittedSealLength, + }, + { + name: "should return SerializedSeal", + sealMap: map[types.Address][]byte{ + ecdsaKeyManager1.Address(): correctCommittedSeal, + }, + expectedRes: &SerializedSeal{ + correctCommittedSeal, + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := ecdsaKeyManager1.GenerateCommittedSeals( + test.sealMap, + nil, + ) + + assert.Equal(t, test.expectedRes, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +func TestECDSAKeyManagerVerifyCommittedSeals(t *testing.T) { + t.Parallel() + + ecdsaKeyManager1, _ := newTestECDSAKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctCommittedSeal, err := ecdsaKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + tests := []struct { + name string + committedSeals Seals + digest []byte + rawSet validators.Validators + expectedRes int + expectedErr error + }{ + { + name: "should return ErrInvalidCommittedSealType if the Seals is not *SerializedSeal", + committedSeals: &AggregatedSeal{}, + digest: msg, + rawSet: nil, + expectedRes: 0, + expectedErr: ErrInvalidCommittedSealType, + }, + { + name: "should return ErrInvalidValidators if the rawSet is not *validators.ECDSAValidators", + committedSeals: &SerializedSeal{}, + digest: msg, + rawSet: validators.NewBLSValidatorSet(), + expectedRes: 0, + expectedErr: ErrInvalidValidators, + }, + { + name: "should return size of CommittedSeals if verification is successful", + committedSeals: &SerializedSeal{ + correctCommittedSeal, + }, + digest: msg, + rawSet: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + ecdsaKeyManager1.Address(), + ), + ), + expectedRes: 1, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := ecdsaKeyManager1.VerifyCommittedSeals( + test.committedSeals, + test.digest, + test.rawSet, + ) + + assert.Equal(t, test.expectedRes, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +func TestECDSAKeyManagerSignIBFTMessageAndEcrecover(t *testing.T) { + t.Parallel() + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + msg := crypto.Keccak256([]byte("message")) + + proposerSeal, err := ecdsaKeyManager.SignIBFTMessage(msg) + assert.NoError(t, err) + + recoveredAddress, err := ecdsaKeyManager.Ecrecover(proposerSeal, msg) + assert.NoError(t, err) + + assert.Equal( + t, + ecdsaKeyManager.Address(), + recoveredAddress, + ) +} + +func TestECDSAKeyManager_verifyCommittedSealsImpl(t *testing.T) { + t.Parallel() + + ecdsaKeyManager1, _ := newTestECDSAKeyManager(t) + ecdsaKeyManager2, _ := newTestECDSAKeyManager(t) + + msg := crypto.Keccak256( + wrapCommitHash( + hex.MustDecodeHex(testHeaderHashHex), + ), + ) + + correctCommittedSeal, err := ecdsaKeyManager1.SignCommittedSeal(msg) + assert.NoError(t, err) + + nonValidatorsCommittedSeal, err := ecdsaKeyManager2.SignCommittedSeal(msg) + assert.NoError(t, err) + + wrongSignature := []byte("fake") + + tests := []struct { + name string + committedSeals *SerializedSeal + msg []byte + validators validators.Validators + expectedRes int + expectedErr error + }{ + { + name: "should return ErrInvalidCommittedSealType if the Seals is not *SerializedSeal", + committedSeals: &SerializedSeal{}, + msg: msg, + validators: validators.NewECDSAValidatorSet(), + expectedRes: 0, + expectedErr: ErrEmptyCommittedSeals, + }, + { + name: "should return error if Ecrecover failed", + committedSeals: &SerializedSeal{ + wrongSignature, + }, + msg: msg, + validators: validators.NewECDSAValidatorSet(), + expectedRes: 0, + expectedErr: errors.New("invalid compact signature size"), + }, + { + name: "should return error ErrRepeatedCommittedSeal if CommittedSeal", + committedSeals: &SerializedSeal{ + correctCommittedSeal, + correctCommittedSeal, + }, + msg: msg, + validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + ecdsaKeyManager1.Address(), + ), + ), + expectedRes: 0, + expectedErr: ErrRepeatedCommittedSeal, + }, + { + name: "should return error ErrNonValidatorCommittedSeal if CommittedSeals has the signature by non-validator", + committedSeals: &SerializedSeal{ + correctCommittedSeal, + nonValidatorsCommittedSeal, + }, + msg: msg, + validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + ecdsaKeyManager1.Address(), + ), + ), + expectedRes: 0, + expectedErr: ErrNonValidatorCommittedSeal, + }, + { + name: "should return the size of CommittedSeals if verification is successful", + committedSeals: &SerializedSeal{ + correctCommittedSeal, + }, + msg: msg, + validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + ecdsaKeyManager1.Address(), + ), + ), + expectedRes: 1, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := ecdsaKeyManager1.(*ECDSAKeyManager).verifyCommittedSealsImpl( + test.committedSeals, + test.msg, + test.validators, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} diff --git a/consensus/ibft/signer/extra.go b/consensus/ibft/signer/extra.go new file mode 100644 index 0000000000..39583c3576 --- /dev/null +++ b/consensus/ibft/signer/extra.go @@ -0,0 +1,250 @@ +package signer + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/umbracle/fastrlp" +) + +var ( + // IstanbulDigest represents a hash of "Istanbul practical byzantine fault tolerance" + // to identify whether the block is from Istanbul consensus engine + IstanbulDigest = types.StringToHash("0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365") + + // IstanbulExtraVanity represents a fixed number of extra-data bytes reserved for proposer vanity + IstanbulExtraVanity = 32 + + // IstanbulExtraSeal represents the fixed number of extra-data bytes reserved for proposer seal + IstanbulExtraSeal = 65 + + zeroBytes = make([]byte, 32) +) + +// IstanbulExtra defines the structure of the extra field for Istanbul +type IstanbulExtra struct { + Validators validators.Validators + ProposerSeal []byte + CommittedSeals Seals + ParentCommittedSeals Seals +} + +type Seals interface { + // Number of committed seals + Num() int + MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value + UnmarshalRLPFrom(*fastrlp.Parser, *fastrlp.Value) error +} + +// MarshalRLPTo defines the marshal function wrapper for IstanbulExtra +func (i *IstanbulExtra) MarshalRLPTo(dst []byte) []byte { + return types.MarshalRLPTo(i.MarshalRLPWith, dst) +} + +// MarshalRLPWith defines the marshal function implementation for IstanbulExtra +func (i *IstanbulExtra) MarshalRLPWith(ar *fastrlp.Arena) *fastrlp.Value { + vv := ar.NewArray() + + // Validators + vv.Set(i.Validators.MarshalRLPWith(ar)) + + // ProposerSeal + if len(i.ProposerSeal) == 0 { + vv.Set(ar.NewNull()) + } else { + vv.Set(ar.NewCopyBytes(i.ProposerSeal)) + } + + // CommittedSeal + vv.Set(i.CommittedSeals.MarshalRLPWith(ar)) + + // ParentCommittedSeal + if i.ParentCommittedSeals != nil { + vv.Set(i.ParentCommittedSeals.MarshalRLPWith(ar)) + } + + return vv +} + +// UnmarshalRLP defines the unmarshal function wrapper for IstanbulExtra +func (i *IstanbulExtra) UnmarshalRLP(input []byte) error { + return types.UnmarshalRlp(i.UnmarshalRLPFrom, input) +} + +// UnmarshalRLPFrom defines the unmarshal implementation for IstanbulExtra +func (i *IstanbulExtra) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error { + elems, err := v.GetElems() + if err != nil { + return err + } + + if len(elems) < 3 { + return fmt.Errorf("incorrect number of elements to decode istambul extra, expected 3 but found %d", len(elems)) + } + + // Validators + if err := i.Validators.UnmarshalRLPFrom(p, elems[0]); err != nil { + return err + } + + // ProposerSeal + if i.ProposerSeal, err = elems[1].GetBytes(i.ProposerSeal); err != nil { + return fmt.Errorf("failed to decode Seal: %w", err) + } + + // CommittedSeal + if err := i.CommittedSeals.UnmarshalRLPFrom(p, elems[2]); err != nil { + return err + } + + // ParentCommitted + if len(elems) >= 4 && i.ParentCommittedSeals != nil { + if err := i.ParentCommittedSeals.UnmarshalRLPFrom(p, elems[3]); err != nil { + return err + } + } + + return nil +} + +// UnmarshalRLPForParentCS defines the unmarshal function wrapper for IstanbulExtra +// that parses only Parent Committed Seals +func (i *IstanbulExtra) unmarshalRLPForParentCS(input []byte) error { + return types.UnmarshalRlp(i.unmarshalRLPFromForParentCS, input) +} + +// UnmarshalRLPFrom defines the unmarshal implementation for IstanbulExtra +// that parses only Parent Committed Seals +func (i *IstanbulExtra) unmarshalRLPFromForParentCS(p *fastrlp.Parser, v *fastrlp.Value) error { + elems, err := v.GetElems() + if err != nil { + return err + } + + // ParentCommitted + if len(elems) >= 4 { + if err := i.ParentCommittedSeals.UnmarshalRLPFrom(p, elems[3]); err != nil { + return err + } + } + + return nil +} + +// putIbftExtra sets the IBFT extra data field into the header +func putIbftExtra(h *types.Header, istanbulExtra *IstanbulExtra) { + // Pad zeros to the right up to istanbul vanity + extra := h.ExtraData + if len(extra) < IstanbulExtraVanity { + extra = append(extra, zeroBytes[:IstanbulExtraVanity-len(extra)]...) + } else { + extra = extra[:IstanbulExtraVanity] + } + + h.ExtraData = istanbulExtra.MarshalRLPTo(extra) +} + +// packFieldsIntoExtra is a helper function +// that injects a few fields into IBFT Extra +// without modifying other fields +// Validators, CommittedSeals, and ParentCommittedSeals have a few types +// and extra must have these instances before unmarshalling usually +// This function doesn't require the field instances that don't update +func packFieldsIntoExtra( + extraBytes []byte, + packFn func( + ar *fastrlp.Arena, + oldValues []*fastrlp.Value, + newArrayValue *fastrlp.Value, + ) error, +) []byte { + extraHeader := extraBytes[:IstanbulExtraVanity] + extraBody := extraBytes[IstanbulExtraVanity:] + + newExtraBody := types.MarshalRLPTo(func(ar *fastrlp.Arena) *fastrlp.Value { + vv := ar.NewArray() + + _ = types.UnmarshalRlp(func(p *fastrlp.Parser, v *fastrlp.Value) error { + elems, err := v.GetElems() + if err != nil { + return err + } + + if len(elems) < 3 { + return fmt.Errorf("incorrect number of elements to decode istambul extra, expected 3 but found %d", len(elems)) + } + + return packFn(ar, elems, vv) + }, extraBody) + + return vv + }, nil) + + return append( + extraHeader, + newExtraBody..., + ) +} + +// packProposerSealIntoExtra updates only Seal field in Extra +func packProposerSealIntoExtra( + extraBytes []byte, + proposerSeal []byte, +) []byte { + return packFieldsIntoExtra( + extraBytes, + func( + ar *fastrlp.Arena, + oldValues []*fastrlp.Value, + newArrayValue *fastrlp.Value, + ) error { + // Validators + newArrayValue.Set(oldValues[0]) + + // Seal + newArrayValue.Set(ar.NewBytes(proposerSeal)) + + // CommittedSeal + newArrayValue.Set(oldValues[2]) + + // ParentCommittedSeal + if len(oldValues) >= 4 { + newArrayValue.Set(oldValues[3]) + } + + return nil + }, + ) +} + +// packCommittedSealsIntoExtra updates only CommittedSeal field in Extra +func packCommittedSealsIntoExtra( + extraBytes []byte, + committedSeal Seals, +) []byte { + return packFieldsIntoExtra( + extraBytes, + func( + ar *fastrlp.Arena, + oldValues []*fastrlp.Value, + newArrayValue *fastrlp.Value, + ) error { + // Validators + newArrayValue.Set(oldValues[0]) + + // Seal + newArrayValue.Set(oldValues[1]) + + // CommittedSeal + newArrayValue.Set(committedSeal.MarshalRLPWith(ar)) + + // ParentCommittedSeal + if len(oldValues) >= 4 { + newArrayValue.Set(oldValues[3]) + } + + return nil + }, + ) +} diff --git a/consensus/ibft/signer/extra_test.go b/consensus/ibft/signer/extra_test.go new file mode 100644 index 0000000000..ae8035bac5 --- /dev/null +++ b/consensus/ibft/signer/extra_test.go @@ -0,0 +1,505 @@ +package signer + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +func JSONMarshalHelper(t *testing.T, extra *IstanbulExtra) string { + t.Helper() + + res, err := json.Marshal(extra) + + assert.NoError(t, err) + + return string(res) +} + +func TestIstanbulExtraMarshalAndUnmarshal(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + extra *IstanbulExtra + }{ + { + name: "ECDSAExtra", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator( + testAddr1, + ), + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + ParentCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + }, + { + name: "ECDSAExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + }, + }, + { + name: "BLSExtra", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + }, + { + name: "BLSExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + // create original data + originalExtraJSON := JSONMarshalHelper(t, test.extra) + + bytesData := test.extra.MarshalRLPTo(nil) + err := test.extra.UnmarshalRLP(bytesData) + assert.NoError(t, err) + + // make sure all data is recovered + assert.Equal( + t, + originalExtraJSON, + JSONMarshalHelper(t, test.extra), + ) + }) + } +} + +func Test_packProposerSealIntoExtra(t *testing.T) { + t.Parallel() + + newProposerSeal := []byte("new proposer seal") + + tests := []struct { + name string + extra *IstanbulExtra + }{ + { + name: "ECDSAExtra", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + ParentCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + }, + { + name: "ECDSAExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + }, + }, + { + name: "BLSExtra", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + }, + { + name: "BLSExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + originalProposerSeal := test.extra.ProposerSeal + + // create expected data + test.extra.ProposerSeal = newProposerSeal + expectedJSON := JSONMarshalHelper(t, test.extra) + test.extra.ProposerSeal = originalProposerSeal + + newExtraBytes := packProposerSealIntoExtra( + // prepend IstanbulExtraHeader to parse + append( + make([]byte, IstanbulExtraVanity), + test.extra.MarshalRLPTo(nil)..., + ), + newProposerSeal, + ) + + assert.NoError( + t, + test.extra.UnmarshalRLP(newExtraBytes[IstanbulExtraVanity:]), + ) + + // check json of decoded data matches with the original data + jsonData := JSONMarshalHelper(t, test.extra) + + assert.Equal( + t, + expectedJSON, + jsonData, + ) + }) + } +} + +func Test_packCommittedSealsIntoExtra(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + extra *IstanbulExtra + newCommittedSeals Seals + }{ + { + name: "ECDSAExtra", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + ParentCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + newCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + { + name: "ECDSAExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + }, + newCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + { + name: "BLSExtra", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + newCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0xa}), + Signature: []byte{0x2}, + }, + }, + { + name: "BLSExtra without ParentCommittedSeals", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + newCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0xa}), + Signature: []byte{0x2}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + originalCommittedSeals := test.extra.CommittedSeals + + // create expected data + test.extra.CommittedSeals = test.newCommittedSeals + expectedJSON := JSONMarshalHelper(t, test.extra) + test.extra.CommittedSeals = originalCommittedSeals + + // update committed seals + newExtraBytes := packCommittedSealsIntoExtra( + // prepend IstanbulExtraHeader + append( + make([]byte, IstanbulExtraVanity), + test.extra.MarshalRLPTo(nil)..., + ), + test.newCommittedSeals, + ) + + // decode RLP data + assert.NoError( + t, + test.extra.UnmarshalRLP(newExtraBytes[IstanbulExtraVanity:]), + ) + + // check json of decoded data matches with the original data + jsonData := JSONMarshalHelper(t, test.extra) + + assert.Equal( + t, + expectedJSON, + jsonData, + ) + }) + } +} + +func Test_unmarshalRLPForParentCS(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + extra *IstanbulExtra + targetExtra *IstanbulExtra + }{ + { + name: "ECDSAExtra", + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + ParentCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + targetExtra: &IstanbulExtra{ + ParentCommittedSeals: &SerializedSeal{}, + }, + }, + { + name: "BLSExtra", + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + targetExtra: &IstanbulExtra{ + ParentCommittedSeals: &AggregatedSeal{}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + bytesData := test.extra.MarshalRLPTo(nil) + + assert.NoError(t, test.targetExtra.unmarshalRLPForParentCS(bytesData)) + + // make sure all data is recovered + assert.Equal( + t, + test.extra.ParentCommittedSeals, + test.targetExtra.ParentCommittedSeals, + ) + }) + } +} + +func Test_putIbftExtra(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + header *types.Header + extra *IstanbulExtra + }{ + { + name: "ECDSAExtra", + header: &types.Header{ + ExtraData: []byte{}, + }, + extra: &IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &SerializedSeal{ + []byte{0x1}, + []byte{0x2}, + }, + ParentCommittedSeals: &SerializedSeal{ + []byte{0x3}, + []byte{0x4}, + }, + }, + }, + { + name: "BLSExtra", + header: &types.Header{ + ExtraData: make([]byte, IstanbulExtraVanity+10), + }, + extra: &IstanbulExtra{ + Validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + ProposerSeal: testProposerSeal, + CommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x8}), + Signature: []byte{0x1}, + }, + ParentCommittedSeals: &AggregatedSeal{ + Bitmap: new(big.Int).SetBytes([]byte{0x9}), + Signature: []byte{0x2}, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + putIbftExtra(test.header, test.extra) + + expectedExtraHeader := make([]byte, IstanbulExtraVanity) + expectedExtraBody := test.extra.MarshalRLPTo(nil) + expectedExtra := append(expectedExtraHeader, expectedExtraBody...) //nolint:makezero + + assert.Equal( + t, + expectedExtra, + test.header.ExtraData, + ) + }) + } +} diff --git a/consensus/ibft/signer/helper.go b/consensus/ibft/signer/helper.go new file mode 100644 index 0000000000..e97fff68dc --- /dev/null +++ b/consensus/ibft/signer/helper.go @@ -0,0 +1,142 @@ +package signer + +import ( + "crypto/ecdsa" + "fmt" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/keccak" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/secrets/helper" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig" + "github.com/umbracle/fastrlp" +) + +const ( + // legacyCommitCode is the value that is contained in + // legacy committed seals, so it needs to be preserved in order + // for new clients to read old committed seals + legacyCommitCode = 2 +) + +// wrapCommitHash calculates digest for CommittedSeal +func wrapCommitHash(data []byte) []byte { + return crypto.Keccak256(data, []byte{byte(legacyCommitCode)}) +} + +// getOrCreateECDSAKey loads ECDSA key or creates a new key +func getOrCreateECDSAKey(manager secrets.SecretsManager) (*ecdsa.PrivateKey, error) { + if !manager.HasSecret(secrets.ValidatorKey) { + if _, err := helper.InitECDSAValidatorKey(manager); err != nil { + return nil, err + } + } + + keyBytes, err := manager.GetSecret(secrets.ValidatorKey) + if err != nil { + return nil, err + } + + return crypto.BytesToECDSAPrivateKey(keyBytes) +} + +// getOrCreateECDSAKey loads BLS key or creates a new key +func getOrCreateBLSKey(manager secrets.SecretsManager) (*bls_sig.SecretKey, error) { + if !manager.HasSecret(secrets.ValidatorBLSKey) { + if _, err := helper.InitBLSValidatorKey(manager); err != nil { + return nil, err + } + } + + keyBytes, err := manager.GetSecret(secrets.ValidatorBLSKey) + if err != nil { + return nil, err + } + + return crypto.BytesToBLSSecretKey(keyBytes) +} + +// calculateHeaderHash is hash calculation of header for IBFT +func calculateHeaderHash(h *types.Header) types.Hash { + arena := fastrlp.DefaultArenaPool.Get() + defer fastrlp.DefaultArenaPool.Put(arena) + + vv := arena.NewArray() + vv.Set(arena.NewBytes(h.ParentHash.Bytes())) + vv.Set(arena.NewBytes(h.Sha3Uncles.Bytes())) + vv.Set(arena.NewCopyBytes(h.Miner)) + vv.Set(arena.NewBytes(h.StateRoot.Bytes())) + vv.Set(arena.NewBytes(h.TxRoot.Bytes())) + vv.Set(arena.NewBytes(h.ReceiptsRoot.Bytes())) + vv.Set(arena.NewBytes(h.LogsBloom[:])) + vv.Set(arena.NewUint(h.Difficulty)) + vv.Set(arena.NewUint(h.Number)) + vv.Set(arena.NewUint(h.GasLimit)) + vv.Set(arena.NewUint(h.GasUsed)) + vv.Set(arena.NewUint(h.Timestamp)) + vv.Set(arena.NewCopyBytes(h.ExtraData)) + + buf := keccak.Keccak256Rlp(nil, vv) + + return types.BytesToHash(buf) +} + +// ecrecover recovers signer address from the given digest and signature +func ecrecover(sig, msg []byte) (types.Address, error) { + pub, err := crypto.RecoverPubkey(sig, msg) + if err != nil { + return types.Address{}, err + } + + return crypto.PubKeyToAddress(pub), nil +} + +// NewKeyManagerFromType creates KeyManager based on the given type +func NewKeyManagerFromType( + secretManager secrets.SecretsManager, + validatorType validators.ValidatorType, +) (KeyManager, error) { + switch validatorType { + case validators.ECDSAValidatorType: + return NewECDSAKeyManager(secretManager) + case validators.BLSValidatorType: + return NewBLSKeyManager(secretManager) + default: + return nil, fmt.Errorf("unsupported validator type: %s", validatorType) + } +} + +// verifyIBFTExtraSize checks whether header.ExtraData has enough size for IBFT Extra +func verifyIBFTExtraSize(header *types.Header) error { + if len(header.ExtraData) < IstanbulExtraVanity { + return fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + len(header.ExtraData), + ) + } + + return nil +} + +// UseIstanbulHeaderHash is a helper function for the test +func UseIstanbulHeaderHashInTest(t *testing.T, signer Signer) { + t.Helper() + + originalHashCalc := types.HeaderHash + types.HeaderHash = func(h *types.Header) types.Hash { + hash, err := signer.CalculateHeaderHash(h) + if err != nil { + return types.ZeroHash + } + + return hash + } + + t.Cleanup(func() { + types.HeaderHash = originalHashCalc + }) +} diff --git a/consensus/ibft/signer/helper_test.go b/consensus/ibft/signer/helper_test.go new file mode 100644 index 0000000000..4386f63ee7 --- /dev/null +++ b/consensus/ibft/signer/helper_test.go @@ -0,0 +1,456 @@ +package signer + +import ( + "crypto/ecdsa" + "errors" + "fmt" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig" + "github.com/stretchr/testify/assert" +) + +var ( + testHeader = &types.Header{ + ParentHash: types.BytesToHash(crypto.Keccak256([]byte{0x1})), + Sha3Uncles: types.BytesToHash(crypto.Keccak256([]byte{0x2})), + Miner: crypto.Keccak256([]byte{0x3}), + StateRoot: types.BytesToHash(crypto.Keccak256([]byte{0x4})), + TxRoot: types.BytesToHash(crypto.Keccak256([]byte{0x5})), + ReceiptsRoot: types.BytesToHash(crypto.Keccak256([]byte{0x6})), + LogsBloom: types.Bloom{0x7}, + Difficulty: 8, + Number: 9, + GasLimit: 10, + GasUsed: 11, + Timestamp: 12, + ExtraData: crypto.Keccak256([]byte{0x13}), + } + + testHeaderHashHex = "0xd6701b3d601fd78734ce2f2542dc3d9cc1c75b1ed980c61c8d69cd2cb638f89c" +) + +func newTestECDSAKey(t *testing.T) (*ecdsa.PrivateKey, []byte) { + t.Helper() + + testKey, testKeyEncoded, err := crypto.GenerateAndEncodeECDSAPrivateKey() + assert.NoError(t, err, "failed to initialize ECDSA key") + + return testKey, testKeyEncoded +} + +func newTestBLSKey(t *testing.T) (*bls_sig.SecretKey, []byte) { + t.Helper() + + testKey, testKeyEncoded, err := crypto.GenerateAndEncodeBLSSecretKey() + + assert.NoError(t, err, "failed to initialize test ECDSA key") + + return testKey, testKeyEncoded +} + +// Make sure the target function always returns the same result +func Test_wrapCommitHash(t *testing.T) { + t.Parallel() + + var ( + input = crypto.Keccak256([]byte{0x1}) + expectedOutputHex = "0x8a319084d2e52be9c9192645aa98900413ee2a7c93c2916ef99d62218207d1da" + ) + + expectedOutput, err := hex.DecodeHex(expectedOutputHex) + if err != nil { + t.Fatalf("failed to parse expected output: %s, %v", expectedOutputHex, err) + } + + output := wrapCommitHash(input) + + assert.Equal(t, expectedOutput, output) +} + +//nolint +func Test_getOrCreateECDSAKey(t *testing.T) { + t.Parallel() + + testKey, testKeyEncoded := newTestECDSAKey(t) + + testSecretName := func(name string) { + t.Helper() + + // make sure that the correct key is given + assert.Equal(t, secrets.ValidatorKey, name) + } + + //lint:ignore dupl + tests := []struct { + name string + mockSecretManager *MockSecretManager + expectedResult *ecdsa.PrivateKey + expectedErr error + }{ + { + name: "should load ECDSA key from secret manager if the key exists", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return testKeyEncoded, nil + }, + }, + expectedResult: testKey, + expectedErr: nil, + }, + { + name: "should create new ECDSA key if the key doesn't exist", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return false + }, + SetSecretFn: func(name string, key []byte) error { + testSecretName(name) + + assert.NotEqual(t, testKeyEncoded, key) + + return nil + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return testKeyEncoded, nil + }, + }, + expectedResult: testKey, + expectedErr: nil, + }, + { + name: "should return error if secret manager returns error", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return nil, errTest + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + { + name: "should return error if the key manager fails to generate new ECDSA key", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return false + }, + SetSecretFn: func(name string, key []byte) error { + testSecretName(name) + + return errTest + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := getOrCreateECDSAKey(test.mockSecretManager) + + assert.Equal(t, test.expectedResult, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +//nolint +func Test_getOrCreateBLSKey(t *testing.T) { + t.Parallel() + + testKey, testKeyEncoded := newTestBLSKey(t) + + testSecretName := func(name string) { + t.Helper() + + // make sure that the correct key is given + assert.Equal(t, secrets.ValidatorBLSKey, name) + } + + tests := []struct { + name string + mockSecretManager *MockSecretManager + expectedResult *bls_sig.SecretKey + expectedErr error + }{ + { + name: "should load BLS key from secret manager if the key exists", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return testKeyEncoded, nil + }, + }, + expectedResult: testKey, + expectedErr: nil, + }, + { + name: "should create new BLS key if the key doesn't exist", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return false + }, + SetSecretFn: func(name string, key []byte) error { + testSecretName(name) + + assert.NotEqual(t, testKeyEncoded, key) + + return nil + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return testKeyEncoded, nil + }, + }, + expectedResult: testKey, + expectedErr: nil, + }, + { + name: "should return error if secret manager returns error", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + testSecretName(name) + + return nil, errTest + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + { + name: "should return error if the key manager fails to generate new BLS key", + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + testSecretName(name) + + return false + }, + SetSecretFn: func(name string, key []byte) error { + testSecretName(name) + + return errTest + }, + }, + expectedResult: nil, + expectedErr: errTest, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := getOrCreateBLSKey(test.mockSecretManager) + + assert.Equal(t, test.expectedResult, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +// make sure that header hash calculation returns the same hash +func Test_calculateHeaderHash(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + types.StringToHash(testHeaderHashHex), + calculateHeaderHash(testHeader), + ) +} + +func Test_ecrecover(t *testing.T) { + t.Parallel() + + testKey, _ := newTestECDSAKey(t) + signerAddress := crypto.PubKeyToAddress(&testKey.PublicKey) + + rawMessage := crypto.Keccak256([]byte{0x1}) + + signature, err := crypto.Sign( + testKey, + rawMessage, + ) + assert.NoError(t, err) + + recoveredAddress, err := ecrecover(signature, rawMessage) + assert.NoError(t, err) + + assert.Equal( + t, + signerAddress, + recoveredAddress, + ) +} + +func TestNewKeyManagerFromType(t *testing.T) { + t.Parallel() + + testECDSAKey, testECDSAKeyEncoded := newTestECDSAKey(t) + testBLSKey, testBLSKeyEncoded := newTestBLSKey(t) + + tests := []struct { + name string + validatorType validators.ValidatorType + mockSecretManager *MockSecretManager + expectedRes KeyManager + expectedErr error + }{ + { + name: "ECDSAValidatorType", + validatorType: validators.ECDSAValidatorType, + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + return testECDSAKeyEncoded, nil + }, + }, + expectedRes: NewECDSAKeyManagerFromKey(testECDSAKey), + expectedErr: nil, + }, + { + name: "BLSValidatorType", + validatorType: validators.BLSValidatorType, + mockSecretManager: &MockSecretManager{ + HasSecretFn: func(name string) bool { + return true + }, + GetSecretFn: func(name string) ([]byte, error) { + switch name { + case secrets.ValidatorKey: + return testECDSAKeyEncoded, nil + case secrets.ValidatorBLSKey: + return testBLSKeyEncoded, nil + } + + return nil, fmt.Errorf("unexpected key name: %s", name) + }, + }, + expectedRes: NewBLSKeyManagerFromKeys(testECDSAKey, testBLSKey), + }, + { + name: "unsupported type", + validatorType: validators.ValidatorType("fake"), + expectedRes: nil, + expectedErr: errors.New("unsupported validator type: fake"), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := NewKeyManagerFromType(test.mockSecretManager, test.validatorType) + + assert.Equal(t, test.expectedRes, res) + + if test.expectedErr == nil { + assert.NoError(t, err) + } else { + assert.Error(t, err) + assert.ErrorContains(t, err, test.expectedErr.Error()) + } + }) + } +} + +func Test_verifyIBFTExtraSize(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + extraData []byte + isError bool + }{ + { + name: "should return error if ExtraData size is 0", + extraData: make([]byte, 0), + isError: true, + }, + { + name: "should return error if ExtraData size is less than IstanbulExtraVanity", + extraData: make([]byte, IstanbulExtraVanity-1), + isError: true, + }, + { + name: "should return nil if ExtraData size matches with IstanbulExtraVanity", + extraData: make([]byte, IstanbulExtraVanity), + isError: false, + }, + { + name: "should return nil if ExtraData size is greater than IstanbulExtraVanity", + extraData: make([]byte, IstanbulExtraVanity+1), + isError: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + header := &types.Header{ + ExtraData: test.extraData, + } + + err := verifyIBFTExtraSize(header) + + if test.isError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/consensus/ibft/signer/key_manager.go b/consensus/ibft/signer/key_manager.go new file mode 100644 index 0000000000..f5937aca11 --- /dev/null +++ b/consensus/ibft/signer/key_manager.go @@ -0,0 +1,32 @@ +package signer + +import ( + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +// KeyManager is a delegated module that signs data +type KeyManager interface { + // Type returns Validator type signer supports + Type() validators.ValidatorType + // Address returns an address of signer + Address() types.Address + // NewEmptyValidators creates empty validator collection the Signer expects + NewEmptyValidators() validators.Validators + // NewEmptyCommittedSeals creates empty committed seals the Signer expects + NewEmptyCommittedSeals() Seals + // SignProposerSeal creates a signature for ProposerSeal + SignProposerSeal(hash []byte) ([]byte, error) + // SignCommittedSeal creates a signature for committed seal + SignCommittedSeal(hash []byte) ([]byte, error) + // VerifyCommittedSeal verifies a committed seal + VerifyCommittedSeal(vals validators.Validators, signer types.Address, sig, hash []byte) error + // GenerateCommittedSeals creates CommittedSeals from committed seals + GenerateCommittedSeals(sealsByValidator map[types.Address][]byte, vals validators.Validators) (Seals, error) + // VerifyCommittedSeals verifies CommittedSeals + VerifyCommittedSeals(seals Seals, hash []byte, vals validators.Validators) (int, error) + // SignIBFTMessage signs for arbitrary bytes message + SignIBFTMessage(msg []byte) ([]byte, error) + // Ecrecover recovers address from signature and message + Ecrecover(sig []byte, msg []byte) (types.Address, error) +} diff --git a/consensus/ibft/signer/mock_test.go b/consensus/ibft/signer/mock_test.go new file mode 100644 index 0000000000..c74e6359db --- /dev/null +++ b/consensus/ibft/signer/mock_test.go @@ -0,0 +1,88 @@ +package signer + +import ( + "github.com/0xPolygon/polygon-edge/secrets" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +type MockSecretManager struct { + // skip implementing the methods not to be used + secrets.SecretsManager + + HasSecretFn func(string) bool + GetSecretFn func(string) ([]byte, error) + SetSecretFn func(string, []byte) error +} + +func (m *MockSecretManager) HasSecret(name string) bool { + return m.HasSecretFn(name) +} + +func (m *MockSecretManager) GetSecret(name string) ([]byte, error) { + return m.GetSecretFn(name) +} + +func (m *MockSecretManager) SetSecret(name string, key []byte) error { + return m.SetSecretFn(name, key) +} + +type MockKeyManager struct { + TypeFunc func() validators.ValidatorType + AddressFunc func() types.Address + NewEmptyValidatorsFunc func() validators.Validators + NewEmptyCommittedSealsFunc func() Seals + SignProposerSealFunc func([]byte) ([]byte, error) + SignCommittedSealFunc func([]byte) ([]byte, error) + VerifyCommittedSealFunc func(validators.Validators, types.Address, []byte, []byte) error + GenerateCommittedSealsFunc func(map[types.Address][]byte, validators.Validators) (Seals, error) + VerifyCommittedSealsFunc func(Seals, []byte, validators.Validators) (int, error) + SignIBFTMessageFunc func([]byte) ([]byte, error) + EcrecoverFunc func([]byte, []byte) (types.Address, error) +} + +func (m *MockKeyManager) Type() validators.ValidatorType { + return m.TypeFunc() +} + +func (m *MockKeyManager) Address() types.Address { + return m.AddressFunc() +} + +func (m *MockKeyManager) NewEmptyValidators() validators.Validators { + return m.NewEmptyValidatorsFunc() +} + +func (m *MockKeyManager) NewEmptyCommittedSeals() Seals { + return m.NewEmptyCommittedSealsFunc() +} +func (m *MockKeyManager) SignProposerSeal(hash []byte) ([]byte, error) { + return m.SignProposerSealFunc(hash) +} + +func (m *MockKeyManager) SignCommittedSeal(hash []byte) ([]byte, error) { + return m.SignCommittedSealFunc(hash) +} + +func (m *MockKeyManager) VerifyCommittedSeal(vals validators.Validators, signer types.Address, sig, hash []byte) error { + return m.VerifyCommittedSealFunc(vals, signer, sig, hash) +} + +func (m *MockKeyManager) GenerateCommittedSeals( + sealsByValidator map[types.Address][]byte, + vals validators.Validators, +) (Seals, error) { + return m.GenerateCommittedSealsFunc(sealsByValidator, vals) +} + +func (m *MockKeyManager) VerifyCommittedSeals(seals Seals, hash []byte, vals validators.Validators) (int, error) { + return m.VerifyCommittedSealsFunc(seals, hash, vals) +} + +func (m *MockKeyManager) SignIBFTMessage(msg []byte) ([]byte, error) { + return m.SignIBFTMessageFunc(msg) +} + +func (m *MockKeyManager) Ecrecover(sig []byte, msg []byte) (types.Address, error) { + return m.EcrecoverFunc(sig, msg) +} diff --git a/consensus/ibft/signer/signer.go b/consensus/ibft/signer/signer.go new file mode 100644 index 0000000000..9e65d540fb --- /dev/null +++ b/consensus/ibft/signer/signer.go @@ -0,0 +1,383 @@ +package signer + +import ( + "errors" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +var ( + ErrEmptyCommittedSeals = errors.New("empty committed seals") + ErrEmptyParentCommittedSeals = errors.New("empty parent committed seals") + ErrInvalidCommittedSealLength = errors.New("invalid committed seal length") + ErrInvalidCommittedSealType = errors.New("invalid committed seal type") + ErrRepeatedCommittedSeal = errors.New("repeated seal in committed seals") + ErrNonValidatorCommittedSeal = errors.New("found committed seal signed by non validator") + ErrNotEnoughCommittedSeals = errors.New("not enough seals to seal block") + ErrSignerMismatch = errors.New("mismatch address between signer and message sender") + ErrValidatorNotFound = errors.New("validator not found in validator set") + ErrInvalidValidators = errors.New("invalid validators type") + ErrInvalidValidator = errors.New("invalid validator type") + ErrInvalidSignature = errors.New("invalid signature") +) + +// Signer is responsible for signing for blocks and messages in IBFT +type Signer interface { + Type() validators.ValidatorType + Address() types.Address + + // IBFT Extra + InitIBFTExtra(*types.Header, validators.Validators, Seals) + GetIBFTExtra(*types.Header) (*IstanbulExtra, error) + GetValidators(*types.Header) (validators.Validators, error) + + // ProposerSeal + WriteProposerSeal(*types.Header) (*types.Header, error) + EcrecoverFromHeader(*types.Header) (types.Address, error) + + // CommittedSeal + CreateCommittedSeal([]byte) ([]byte, error) + VerifyCommittedSeal(validators.Validators, types.Address, []byte, []byte) error + + // CommittedSeals + WriteCommittedSeals(*types.Header, map[types.Address][]byte) (*types.Header, error) + VerifyCommittedSeals( + header *types.Header, + validators validators.Validators, + quorumSize int, + ) error + + // ParentCommittedSeals + VerifyParentCommittedSeals( + parent, header *types.Header, + parentValidators validators.Validators, + quorum int, + mustExist bool, + ) error + + // IBFTMessage + SignIBFTMessage([]byte) ([]byte, error) + EcrecoverFromIBFTMessage([]byte, []byte) (types.Address, error) + + // Hash of Header + CalculateHeaderHash(*types.Header) (types.Hash, error) +} + +// SignerImpl is an implementation that meets Signer +type SignerImpl struct { + keyManager KeyManager + parentKeyManager KeyManager +} + +// NewSigner is a constructor of SignerImpl +func NewSigner( + keyManager KeyManager, + parentKeyManager KeyManager, +) *SignerImpl { + return &SignerImpl{ + keyManager: keyManager, + parentKeyManager: parentKeyManager, + } +} + +// Type returns that validator type the signer expects +func (s *SignerImpl) Type() validators.ValidatorType { + return s.keyManager.Type() +} + +// Address returns the signer's address +func (s *SignerImpl) Address() types.Address { + return s.keyManager.Address() +} + +// InitIBFTExtra initializes the extra field in the given header +// based on given validators and parent committed seals +func (s *SignerImpl) InitIBFTExtra( + header *types.Header, + validators validators.Validators, + parentCommittedSeals Seals, +) { + s.initIbftExtra( + header, + validators, + parentCommittedSeals, + ) +} + +// GetIBFTExtra extracts IBFT Extra from the given header +func (s *SignerImpl) GetIBFTExtra(header *types.Header) (*IstanbulExtra, error) { + if err := verifyIBFTExtraSize(header); err != nil { + return nil, err + } + + data := header.ExtraData[IstanbulExtraVanity:] + extra := &IstanbulExtra{ + Validators: s.keyManager.NewEmptyValidators(), + ProposerSeal: []byte{}, + CommittedSeals: s.keyManager.NewEmptyCommittedSeals(), + } + + if header.Number > 1 { + extra.ParentCommittedSeals = s.parentKeyManager.NewEmptyCommittedSeals() + } + + if err := extra.UnmarshalRLP(data); err != nil { + return nil, err + } + + return extra, nil +} + +// WriteProposerSeal signs and set ProposerSeal into IBFT Extra of the header +func (s *SignerImpl) WriteProposerSeal(header *types.Header) (*types.Header, error) { + hash, err := s.CalculateHeaderHash(header) + if err != nil { + return nil, err + } + + seal, err := s.keyManager.SignProposerSeal( + crypto.Keccak256(hash.Bytes()), + ) + if err != nil { + return nil, err + } + + header.ExtraData = packProposerSealIntoExtra( + header.ExtraData, + seal, + ) + + return header, nil +} + +// EcrecoverFromIBFTMessage recovers signer address from given signature and header hash +func (s *SignerImpl) EcrecoverFromHeader(header *types.Header) (types.Address, error) { + extra, err := s.GetIBFTExtra(header) + if err != nil { + return types.Address{}, err + } + + return s.keyManager.Ecrecover(extra.ProposerSeal, crypto.Keccak256(header.Hash.Bytes())) +} + +// CreateCommittedSeal returns CommittedSeal from given hash +func (s *SignerImpl) CreateCommittedSeal(hash []byte) ([]byte, error) { + return s.keyManager.SignCommittedSeal( + // Of course, this keccaking of an extended array is not according to the IBFT 2.0 spec, + // but almost nothing in this legacy signing package is. This is kept + // in order to preserve the running chains that used these + // old (and very, very incorrect) signing schemes + crypto.Keccak256( + wrapCommitHash(hash[:]), + ), + ) +} + +// CreateCommittedSeal verifies a CommittedSeal +func (s *SignerImpl) VerifyCommittedSeal( + validators validators.Validators, + signer types.Address, + signature, hash []byte, +) error { + return s.keyManager.VerifyCommittedSeal( + validators, + signer, + signature, + crypto.Keccak256( + wrapCommitHash(hash[:]), + ), + ) +} + +// WriteCommittedSeals builds and writes CommittedSeals into IBFT Extra of the header +func (s *SignerImpl) WriteCommittedSeals( + header *types.Header, + sealMap map[types.Address][]byte, +) (*types.Header, error) { + if len(sealMap) == 0 { + return nil, ErrEmptyCommittedSeals + } + + validators, err := s.GetValidators(header) + if err != nil { + return nil, err + } + + committedSeal, err := s.keyManager.GenerateCommittedSeals(sealMap, validators) + if err != nil { + return nil, err + } + + header.ExtraData = packCommittedSealsIntoExtra( + header.ExtraData, + committedSeal, + ) + + return header, nil +} + +// VerifyCommittedSeals verifies CommittedSeals in IBFT Extra of the header +func (s *SignerImpl) VerifyCommittedSeals( + header *types.Header, + validators validators.Validators, + quorumSize int, +) error { + extra, err := s.GetIBFTExtra(header) + if err != nil { + return err + } + + hash, err := s.CalculateHeaderHash(header) + if err != nil { + return err + } + + rawMsg := crypto.Keccak256( + wrapCommitHash(hash[:]), + ) + + numSeals, err := s.keyManager.VerifyCommittedSeals( + extra.CommittedSeals, + rawMsg, + validators, + ) + if err != nil { + return err + } + + if numSeals < quorumSize { + return ErrNotEnoughCommittedSeals + } + + return nil +} + +// VerifyParentCommittedSeals verifies ParentCommittedSeals in IBFT Extra of the header +func (s *SignerImpl) VerifyParentCommittedSeals( + parent, header *types.Header, + parentValidators validators.Validators, + quorum int, + mustExist bool, +) error { + parentCommittedSeals, err := s.GetParentCommittedSeals(header) + if err != nil { + return err + } + + if parentCommittedSeals == nil || parentCommittedSeals.Num() == 0 { + // Throw error for the proposed header + if mustExist { + return ErrEmptyParentCommittedSeals + } + + // Don't throw if the flag is unset for backward compatibility + // (for the past headers) + return nil + } + + rawMsg := crypto.Keccak256( + wrapCommitHash(parent.Hash.Bytes()), + ) + + numSeals, err := s.keyManager.VerifyCommittedSeals( + parentCommittedSeals, + rawMsg, + parentValidators, + ) + if err != nil { + return err + } + + if numSeals < quorum { + return ErrNotEnoughCommittedSeals + } + + return nil +} + +// SignIBFTMessage signs arbitrary message +func (s *SignerImpl) SignIBFTMessage(msg []byte) ([]byte, error) { + return s.keyManager.SignIBFTMessage(crypto.Keccak256(msg)) +} + +// EcrecoverFromIBFTMessage recovers signer address from given signature and digest +func (s *SignerImpl) EcrecoverFromIBFTMessage(signature, digest []byte) (types.Address, error) { + return s.keyManager.Ecrecover(signature, crypto.Keccak256(digest)) +} + +// InitIBFTExtra initializes the extra field +func (s *SignerImpl) initIbftExtra( + header *types.Header, + validators validators.Validators, + parentCommittedSeal Seals, +) { + putIbftExtra(header, &IstanbulExtra{ + Validators: validators, + ProposerSeal: []byte{}, + CommittedSeals: s.keyManager.NewEmptyCommittedSeals(), + ParentCommittedSeals: parentCommittedSeal, + }) +} + +// CalculateHeaderHash calculates header hash for IBFT Extra +func (s *SignerImpl) CalculateHeaderHash(header *types.Header) (types.Hash, error) { + filteredHeader, err := s.filterHeaderForHash(header) + if err != nil { + return types.ZeroHash, err + } + + return calculateHeaderHash(filteredHeader), nil +} + +func (s *SignerImpl) GetValidators(header *types.Header) (validators.Validators, error) { + extra, err := s.GetIBFTExtra(header) + if err != nil { + return nil, err + } + + return extra.Validators, nil +} + +// GetParentCommittedSeals extracts Parent Committed Seals from IBFT Extra in Header +func (s *SignerImpl) GetParentCommittedSeals(header *types.Header) (Seals, error) { + if err := verifyIBFTExtraSize(header); err != nil { + return nil, err + } + + data := header.ExtraData[IstanbulExtraVanity:] + extra := &IstanbulExtra{ + ParentCommittedSeals: s.keyManager.NewEmptyCommittedSeals(), + } + + if err := extra.unmarshalRLPForParentCS(data); err != nil { + return nil, err + } + + return extra.ParentCommittedSeals, nil +} + +// filterHeaderForHash removes unnecessary fields from IBFT Extra of the header +// for hash calculation +func (s *SignerImpl) filterHeaderForHash(header *types.Header) (*types.Header, error) { + clone := header.Copy() + + extra, err := s.GetIBFTExtra(header) + if err != nil { + return nil, err + } + + parentCommittedSeals := extra.ParentCommittedSeals + if parentCommittedSeals != nil && parentCommittedSeals.Num() == 0 { + // avoid to set ParentCommittedSeals in extra for hash calculation + // in case of empty ParentCommittedSeals for backward compatibility + parentCommittedSeals = nil + } + + // This will effectively remove the Seal and CommittedSeals from the IBFT Extra of header, + // while keeping proposer vanity, validator set, and ParentCommittedSeals + s.initIbftExtra(clone, extra.Validators, parentCommittedSeals) + + return clone, nil +} diff --git a/consensus/ibft/signer/signer_test.go b/consensus/ibft/signer/signer_test.go new file mode 100644 index 0000000000..0291e5f87b --- /dev/null +++ b/consensus/ibft/signer/signer_test.go @@ -0,0 +1,1248 @@ +package signer + +import ( + "errors" + "fmt" + "math/big" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +var ( + errTest = errors.New("test err") + + testAddr1 = types.StringToAddress("1") + testAddr2 = types.StringToAddress("1") + + testBLSPubKey1 = newTestBLSKeyBytes() + testBLSPubKey2 = newTestBLSKeyBytes() + + ecdsaValidator1 = validators.NewECDSAValidator( + testAddr1, + ) + ecdsaValidator2 = validators.NewECDSAValidator( + testAddr2, + ) + + blsValidator1 = validators.NewBLSValidator(testAddr1, testBLSPubKey1) + blsValidator2 = validators.NewBLSValidator(testAddr2, testBLSPubKey2) + + ecdsaValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + blsValidators = validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ) + + testProposerSeal = crypto.Keccak256([]byte{0x1}) + testSerializedSeals1 = &SerializedSeal{[]byte{0x1}, []byte{0x2}} + testSerializedSeals2 = &SerializedSeal{[]byte{0x3}, []byte{0x4}} + testAggregatedSeals1 = newTestAggregatedSeals([]int{0, 1}, []byte{0x12}) + testAggregatedSeals2 = newTestAggregatedSeals([]int{2, 3}, []byte{0x23}) +) + +func newTestAggregatedSeals(bitFlags []int, signature []byte) *AggregatedSeal { + bitMap := new(big.Int) + for _, idx := range bitFlags { + bitMap = bitMap.SetBit(bitMap, idx, 1) + } + + return &AggregatedSeal{ + Bitmap: bitMap, + Signature: signature, + } +} + +func newTestBLSKeyBytes() validators.BLSValidatorPublicKey { + key, err := crypto.GenerateBLSKey() + if err != nil { + return nil + } + + pubKey, err := key.GetPublicKey() + if err != nil { + return nil + } + + buf, err := pubKey.MarshalBinary() + if err != nil { + return nil + } + + return buf +} + +func newTestSingleKeyManagerSigner(km KeyManager) *SignerImpl { + return &SignerImpl{ + keyManager: km, + parentKeyManager: km, + } +} + +func getTestExtraBytes( + validators validators.Validators, + proposerSeal []byte, + committedSeals Seals, + parentCommittedSeals Seals, +) []byte { + extra := &IstanbulExtra{ + Validators: validators, + ProposerSeal: proposerSeal, + CommittedSeals: committedSeals, + ParentCommittedSeals: parentCommittedSeals, + } + + return append( + make([]byte, IstanbulExtraVanity), + extra.MarshalRLPTo(nil)..., + ) +} + +func TestNewKeyManager(t *testing.T) { + t.Parallel() + + keyManager := &MockKeyManager{} + parentKeyManager := &MockKeyManager{} + + signer := NewSigner(keyManager, parentKeyManager) + + assert.Same( + t, + keyManager, + signer.keyManager, + ) + + assert.Same( + t, + parentKeyManager, + signer.parentKeyManager, + ) +} + +func TestSignerType(t *testing.T) { + t.Parallel() + + validatorType := validators.ECDSAValidatorType + signer := newTestSingleKeyManagerSigner( + &MockKeyManager{ + TypeFunc: func() validators.ValidatorType { + return validatorType + }, + }, + ) + + assert.Equal( + t, + validatorType, + signer.Type(), + ) +} + +func TestSignerAddress(t *testing.T) { + t.Parallel() + + addr := testAddr1 + signer := newTestSingleKeyManagerSigner( + &MockKeyManager{ + AddressFunc: func() types.Address { + return addr + }, + }, + ) + + assert.Equal( + t, + addr, + signer.Address(), + ) +} + +func TestSignerInitIBFTExtra(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators validators.Validators + committedSeals Seals + parentCommittedSeals Seals + }{ + { + name: "ECDSA Serialized Seals", + validators: ecdsaValidators, + committedSeals: &SerializedSeal{}, + parentCommittedSeals: testSerializedSeals1, + }, + { + name: "BLS Aggregated Seals", + validators: blsValidators, + committedSeals: &AggregatedSeal{}, + parentCommittedSeals: testAggregatedSeals1, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + header := &types.Header{} + + signer := newTestSingleKeyManagerSigner( + &MockKeyManager{ + NewEmptyCommittedSealsFunc: func() Seals { + return test.committedSeals + }, + }, + ) + + signer.InitIBFTExtra( + header, + test.validators, + test.parentCommittedSeals, + ) + + expectedExtraBytes := getTestExtraBytes( + test.validators, + []byte{}, + test.committedSeals, + test.parentCommittedSeals, + ) + + assert.Equal( + t, + expectedExtraBytes, + header.ExtraData, + ) + }) + } +} + +func TestSignerGetIBFTExtra(t *testing.T) { + tests := []struct { + name string + header *types.Header + signer *SignerImpl + expectedExtra *IstanbulExtra + expectedErr error + }{ + { + name: "should return error if the size of header.ExtraData is less than IstanbulExtraVanity", + header: &types.Header{ + ExtraData: []byte{}, + }, + signer: NewSigner(nil, nil), + expectedExtra: nil, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return IstanbulExtra for the header at 1 (ECDSA Serialized Seal)", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + nil, + ), + expectedExtra: &IstanbulExtra{ + Validators: ecdsaValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testSerializedSeals1, + ParentCommittedSeals: nil, + }, + expectedErr: nil, + }, + { + name: "should return IstanbulExtra for the header at 1 (BLS Aggregated Seals)", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + blsValidators, + testProposerSeal, + testAggregatedSeals1, + nil, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return blsValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &AggregatedSeal{} + }, + }, + nil, + ), + expectedExtra: &IstanbulExtra{ + Validators: blsValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testAggregatedSeals1, + ParentCommittedSeals: nil, + }, + expectedErr: nil, + }, + { + name: "should return IstanbulExtra with ParentCommittedSeals for the header at 2 (ECDSA Serialized Seal)", + header: &types.Header{ + Number: 2, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + testSerializedSeals2, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + &MockKeyManager{ + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + ), + expectedExtra: &IstanbulExtra{ + Validators: ecdsaValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testSerializedSeals1, + ParentCommittedSeals: testSerializedSeals2, + }, + expectedErr: nil, + }, + { + name: "should return IstanbulExtra with ParentCommittedSeals for the header at 2 (BLS Aggregated Seal)", + header: &types.Header{ + Number: 2, + ExtraData: getTestExtraBytes( + blsValidators, + testProposerSeal, + testAggregatedSeals1, + testAggregatedSeals2, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return blsValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &AggregatedSeal{} + }, + }, + &MockKeyManager{ + NewEmptyCommittedSealsFunc: func() Seals { + return &AggregatedSeal{} + }, + }, + ), + expectedExtra: &IstanbulExtra{ + Validators: blsValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testAggregatedSeals1, + ParentCommittedSeals: testAggregatedSeals2, + }, + expectedErr: nil, + }, + { + name: "should return IstanbulExtra for BLS even if parent committed seals is created by ECDSA", + header: &types.Header{ + Number: 3, + ExtraData: getTestExtraBytes( + blsValidators, + testProposerSeal, + testAggregatedSeals1, + testSerializedSeals1, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return blsValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &AggregatedSeal{} + }, + }, + &MockKeyManager{ + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + ), + expectedExtra: &IstanbulExtra{ + Validators: blsValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testAggregatedSeals1, + ParentCommittedSeals: testSerializedSeals1, + }, + expectedErr: nil, + }, + { + name: "should return IstanbulExtra for ECDSA even if parent committed seals is created by BLS", + header: &types.Header{ + Number: 3, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + testAggregatedSeals1, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + &MockKeyManager{ + NewEmptyCommittedSealsFunc: func() Seals { + return &AggregatedSeal{} + }, + }, + ), + expectedExtra: &IstanbulExtra{ + Validators: ecdsaValidators, + ProposerSeal: testProposerSeal, + CommittedSeals: testSerializedSeals1, + ParentCommittedSeals: testAggregatedSeals1, + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + extra, err := test.signer.GetIBFTExtra(test.header) + + assert.Equal( + t, + test.expectedExtra, + extra, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestSignerWriteProposerSeal(t *testing.T) { + tests := []struct { + name string + header *types.Header + signer *SignerImpl + expectedHeader *types.Header + expectedErr error + }{ + { + name: "should return error if GetIBFTExtra fails", + header: &types.Header{ + ExtraData: []byte{}, + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + nil, + ), + expectedHeader: nil, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return error if SignProposerSeal returns error", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + SignProposerSealFunc: func(b []byte) ([]byte, error) { + return nil, errTest + }, + }, + nil, + ), + expectedHeader: nil, + expectedErr: errTest, + }, + { + name: "should set ProposerSeal into Header", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + nil, + testSerializedSeals1, + nil, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + SignProposerSealFunc: func(b []byte) ([]byte, error) { + return testProposerSeal, nil + }, + }, + nil, + ), + expectedHeader: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + UseIstanbulHeaderHashInTest(t, test.signer) + + header, err := test.signer.WriteProposerSeal(test.header) + + assert.Equal( + t, + test.expectedHeader, + header, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestSignerEcrecoverFromHeader(t *testing.T) { + tests := []struct { + name string + header *types.Header + signer *SignerImpl + expectedAddr types.Address + expectedErr error + }{ + { + name: "should return error if GetIBFTExtra fails", + header: &types.Header{ + Number: 0, + ExtraData: []byte{}, + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + }, + nil, + ), + expectedAddr: types.ZeroAddress, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return address", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + signer: NewSigner( + &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + EcrecoverFunc: func(b1, b2 []byte) (types.Address, error) { + return ecdsaValidator1.Address, nil + }, + }, + nil, + ), + expectedAddr: ecdsaValidator1.Address, + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + UseIstanbulHeaderHashInTest(t, test.signer) + + addr, err := test.signer.EcrecoverFromHeader(test.header) + + assert.Equal( + t, + test.expectedAddr, + addr, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + err, + ) + }) + } +} + +func TestSignerCreateCommittedSeal(t *testing.T) { + t.Parallel() + + hash := crypto.Keccak256([]byte{0x1}) + sig := crypto.Keccak256([]byte{0x2}) + + signer := newTestSingleKeyManagerSigner( + &MockKeyManager{ + SignCommittedSealFunc: func(b []byte) ([]byte, error) { + assert.Equal( + t, + crypto.Keccak256(wrapCommitHash(hash)), + b, + ) + + return sig, nil + }, + }, + ) + + res, err := signer.CreateCommittedSeal(hash) + + assert.Equal(t, sig, res) + assert.NoError(t, err) +} + +func TestVerifyCommittedSeal(t *testing.T) { + t.Parallel() + + hash := crypto.Keccak256([]byte{0x1}) + sig := crypto.Keccak256([]byte{0x2}) + + signer := newTestSingleKeyManagerSigner( + &MockKeyManager{ + VerifyCommittedSealFunc: func(vals validators.Validators, author types.Address, s, h []byte) error { + assert.Equal(t, ecdsaValidators, vals) + assert.Equal(t, testAddr1, author) + assert.Equal(t, sig, s) + assert.Equal(t, crypto.Keccak256( + wrapCommitHash(hash[:]), + ), h) + + return errTest + }, + }, + ) + + assert.Equal( + t, + errTest, + signer.VerifyCommittedSeal( + ecdsaValidators, + testAddr1, + sig, + hash, + ), + ) +} + +func TestSignerWriteCommittedSeals(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + header *types.Header + sealMap map[types.Address][]byte + keyManager *MockKeyManager + expectedHeader *types.Header + expectedErr error + }{ + { + name: "should return ErrEmptyCommittedSeals if sealMap is empty", + header: &types.Header{}, + sealMap: map[types.Address][]byte{}, + keyManager: nil, + expectedHeader: nil, + expectedErr: ErrEmptyCommittedSeals, + }, + { + name: "should return error if GetValidators fails", + header: &types.Header{}, + sealMap: map[types.Address][]byte{ + testAddr1: []byte("test"), + }, + keyManager: nil, + expectedHeader: nil, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return error if GenerateCommittedSeals fails", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + &SerializedSeal{}, + nil, + ), + }, + sealMap: map[types.Address][]byte{ + testAddr1: []byte("test"), + }, + keyManager: &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + GenerateCommittedSealsFunc: func(m map[types.Address][]byte, v validators.Validators) (Seals, error) { + return nil, errTest + }, + }, + expectedHeader: nil, + expectedErr: errTest, + }, + { + name: "should set CommittedSeals into IBFTExtra", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + &SerializedSeal{}, + nil, + ), + }, + sealMap: map[types.Address][]byte{ + testAddr1: []byte("test"), + }, + keyManager: &MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + GenerateCommittedSealsFunc: func(m map[types.Address][]byte, v validators.Validators) (Seals, error) { + return testSerializedSeals1, nil + }, + }, + expectedHeader: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + signer := newTestSingleKeyManagerSigner(test.keyManager) + + header, err := signer.WriteCommittedSeals(test.header, test.sealMap) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + err, + ) + assert.Equal( + t, + test.expectedHeader, + header, + ) + }) + } +} + +func TestSignerVerifyCommittedSeals(t *testing.T) { + tests := []struct { + name string + header *types.Header + validators validators.Validators + quorumSize int + verifyCommittedSealsRes int + verifyCommittedSealsErr error + expectedErr error + }{ + { + name: "should return error if GetIBFTExtra fails", + header: &types.Header{}, + validators: ecdsaValidators, + quorumSize: 0, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: nil, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return error if VerifyCommittedSeals fails", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + validators: ecdsaValidators, + quorumSize: 0, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: errTest, + expectedErr: errTest, + }, + { + name: "should return error if number of signers is less than quorumSize", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + validators: ecdsaValidators, + quorumSize: 5, + verifyCommittedSealsRes: 3, + verifyCommittedSealsErr: nil, + expectedErr: ErrNotEnoughCommittedSeals, + }, + { + name: "should succeed", + header: &types.Header{ + Number: 1, + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + validators: ecdsaValidators, + quorumSize: 5, + verifyCommittedSealsRes: 6, + verifyCommittedSealsErr: nil, + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var expectedSig []byte + + signer := newTestSingleKeyManagerSigner(&MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return test.validators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + VerifyCommittedSealsFunc: func(s Seals, b []byte, v validators.Validators) (int, error) { + assert.Equal(t, testSerializedSeals1, s) + assert.Equal(t, ecdsaValidators, v) + assert.Equal(t, expectedSig, b) + + return test.verifyCommittedSealsRes, test.verifyCommittedSealsErr + }, + }) + + UseIstanbulHeaderHashInTest(t, signer) + + expectedSig = crypto.Keccak256( + wrapCommitHash( + test.header.ComputeHash().Hash.Bytes(), + ), + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + signer.VerifyCommittedSeals(test.header, test.validators, test.quorumSize), + ) + }) + } +} + +func TestSignerVerifyParentCommittedSeals(t *testing.T) { + t.Parallel() + + parentHeaderHash := crypto.Keccak256(types.ZeroAddress.Bytes()) + + tests := []struct { + name string + parentHeader *types.Header + header *types.Header + parentValidators validators.Validators + quorumSize int + mustExist bool + verifyCommittedSealsRes int + verifyCommittedSealsErr error + expectedErr error + }{ + { + name: "should return error if GetIBFTExtra fails", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: []byte{}, + }, + parentValidators: ecdsaValidators, + quorumSize: 0, + mustExist: true, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: nil, + expectedErr: fmt.Errorf( + "wrong extra size, expected greater than or equal to %d but actual %d", + IstanbulExtraVanity, + 0, + ), + }, + { + name: "should return error if header doesn't have ParentCommittedSeals and must exist is true", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + parentValidators: ecdsaValidators, + quorumSize: 0, + mustExist: true, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: nil, + expectedErr: ErrEmptyParentCommittedSeals, + }, + { + name: "should succeed if header doesn't have ParentCommittedSeals and must exist is false", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + nil, + ), + }, + parentValidators: ecdsaValidators, + quorumSize: 0, + mustExist: false, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: nil, + expectedErr: nil, + }, + { + name: "should return error if VerifyCommittedSeals fails", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + testSerializedSeals2, + ), + }, + parentValidators: ecdsaValidators, + quorumSize: 0, + mustExist: false, + verifyCommittedSealsRes: 0, + verifyCommittedSealsErr: errTest, + expectedErr: errTest, + }, + { + name: "should return ErrNotEnoughCommittedSeals if the number of signers is less than quorum", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + testSerializedSeals2, + ), + }, + parentValidators: ecdsaValidators, + quorumSize: 5, + mustExist: false, + verifyCommittedSealsRes: 2, + verifyCommittedSealsErr: nil, + expectedErr: ErrNotEnoughCommittedSeals, + }, + { + name: "should succeed", + parentHeader: &types.Header{ + Hash: types.BytesToHash(parentHeaderHash), + }, + header: &types.Header{ + ExtraData: getTestExtraBytes( + ecdsaValidators, + testProposerSeal, + testSerializedSeals1, + testSerializedSeals2, + ), + }, + parentValidators: ecdsaValidators, + quorumSize: 5, + mustExist: false, + verifyCommittedSealsRes: 6, + verifyCommittedSealsErr: nil, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + expectedSig := crypto.Keccak256( + wrapCommitHash( + test.parentHeader.Hash.Bytes(), + ), + ) + + signer := newTestSingleKeyManagerSigner(&MockKeyManager{ + NewEmptyValidatorsFunc: func() validators.Validators { + return ecdsaValidators + }, + NewEmptyCommittedSealsFunc: func() Seals { + return &SerializedSeal{} + }, + VerifyCommittedSealsFunc: func(s Seals, b []byte, v validators.Validators) (int, error) { + assert.Equal(t, testSerializedSeals2, s) + assert.Equal(t, ecdsaValidators, v) + assert.Equal(t, expectedSig, b) + + return test.verifyCommittedSealsRes, test.verifyCommittedSealsErr + }, + }) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + signer.VerifyParentCommittedSeals( + test.parentHeader, + test.header, + test.parentValidators, + test.quorumSize, + test.mustExist, + ), + ) + }) + } +} + +func TestSignerSignIBFTMessage(t *testing.T) { + t.Parallel() + + msg := []byte("test") + sig := []byte("signature") + + signer := &SignerImpl{ + keyManager: &MockKeyManager{ + SignIBFTMessageFunc: func(data []byte) ([]byte, error) { + assert.Equal(t, crypto.Keccak256(msg), data) + + return sig, errTest + }, + }, + } + + res, err := signer.SignIBFTMessage(msg) + + assert.Equal( + t, + sig, + res, + ) + + assert.Equal( + t, + errTest, + err, + ) +} + +func TestEcrecoverFromIBFTMessage(t *testing.T) { + t.Parallel() + + msg := []byte("test") + sig := []byte("signature") + + signer := &SignerImpl{ + keyManager: &MockKeyManager{ + EcrecoverFunc: func(b1, b2 []byte) (types.Address, error) { + assert.Equal(t, sig, b1) + assert.Equal(t, crypto.Keccak256(msg), b2) + + return testAddr1, errTest + }, + }, + } + + res, err := signer.EcrecoverFromIBFTMessage(sig, msg) + + assert.Equal( + t, + testAddr1, + res, + ) + + assert.Equal( + t, + errTest, + err, + ) +} + +func TestSignerSignIBFTMessageAndEcrecoverFromIBFTMessage(t *testing.T) { + t.Parallel() + + msg := []byte("message") + + ecdsaKeyManager, _ := newTestECDSAKeyManager(t) + blsKeyManager, _, _ := newTestBLSKeyManager(t) + + tests := []struct { + name string + keyManager KeyManager + }{ + { + name: "ECDSA Signer", + keyManager: ecdsaKeyManager, + }, + { + name: "BLS Signer", + keyManager: blsKeyManager, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + signer := newTestSingleKeyManagerSigner(test.keyManager) + + sig, err := signer.SignIBFTMessage(msg) + assert.NoError(t, err) + + recovered, err := signer.EcrecoverFromIBFTMessage(sig, msg) + assert.NoError(t, err) + + assert.Equal( + t, + signer.Address(), + recovered, + ) + }) + } +} diff --git a/consensus/ibft/snapshot.go b/consensus/ibft/snapshot.go deleted file mode 100644 index 6e7d6145fa..0000000000 --- a/consensus/ibft/snapshot.go +++ /dev/null @@ -1,580 +0,0 @@ -package ibft - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "sync" - "sync/atomic" - - lru "github.com/hashicorp/golang-lru" - - "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" - "github.com/0xPolygon/polygon-edge/types" - "github.com/hashicorp/go-hclog" -) - -var ( - errMetadataNotFound = errors.New("snapshot metadata not found") - errSnapshotNotFound = errors.New("snapshot not found") - errParentSnapshotNotFound = errors.New("parent snapshot not found") -) - -// setupSnapshot sets up the snapshot store for the IBFT object -func (i *backendIBFT) setupSnapshot() error { - i.store = newSnapshotStore() - - // Read from storage - if i.config.Path != "" { - if err := i.store.loadFromPath(i.config.Path, i.logger); err != nil { - return err - } - } - - header := i.blockchain.Header() - meta := i.getSnapshotMetadata() - - if meta == nil { - return errMetadataNotFound - } - - if header.Number == 0 { - // Add genesis - if err := i.addHeaderSnap(header); err != nil { - return err - } - } - - // If the snapshot is not found, or the latest snapshot belongs to a previous epoch, - // we need to start rebuilding the snapshot from the beginning of the current epoch - // in order to have all the votes and validators correctly set in the snapshot, - // since they reset every epoch. - - // Get epoch of latest header and saved metadata - currentEpoch := header.Number / i.epochSize - metaEpoch := meta.LastBlock / i.epochSize - snapshot := i.getSnapshot(header.Number) - - if snapshot == nil || metaEpoch < currentEpoch { - // Restore snapshot at the beginning of the current epoch by block header - // if list doesn't have any snapshots to calculate snapshot for the next header - i.logger.Info("snapshot was not found, restore snapshot at beginning of current epoch", "current epoch", currentEpoch) - beginHeight := currentEpoch * i.epochSize - beginHeader, ok := i.blockchain.GetHeaderByNumber(beginHeight) - - if !ok { - return fmt.Errorf("header at %d not found", beginHeight) - } - - if err := i.addHeaderSnap(beginHeader); err != nil { - return err - } - - i.store.updateLastBlock(beginHeight) - - if meta = i.getSnapshotMetadata(); meta == nil { - return errMetadataNotFound - } - } - - // Process headers if we missed some blocks in the current epoch - if header.Number > meta.LastBlock { - i.logger.Info("syncing past snapshots", "from", meta.LastBlock, "to", header.Number) - - for num := meta.LastBlock + 1; num <= header.Number; num++ { - if num == 0 { - continue - } - - header, ok := i.blockchain.GetHeaderByNumber(num) - if !ok { - return fmt.Errorf("header %d not found", num) - } - - if err := i.processHeaders([]*types.Header{header}); err != nil { - return err - } - } - } - - return nil -} - -// addHeaderSnap creates the initial snapshot, and adds it to the snapshot store -func (i *backendIBFT) addHeaderSnap(header *types.Header) error { - // Genesis header needs to be set by hand, all the other - // snapshots are set as part of processHeaders - extra, err := getIbftExtra(header) - if err != nil { - return err - } - - // Create the first snapshot from the genesis - snap := &Snapshot{ - Hash: header.Hash.String(), - Number: header.Number, - Votes: []*Vote{}, - Set: extra.Validators, - } - - i.store.add(snap) - - return nil -} - -// getLatestSnapshot returns the latest snapshot object -func (i *backendIBFT) getLatestSnapshot() (*Snapshot, error) { - meta := i.getSnapshotMetadata() - if meta == nil { - return nil, errMetadataNotFound - } - - snap := i.getSnapshot(meta.LastBlock) - if snap == nil { - return nil, errSnapshotNotFound - } - - return snap, nil -} - -// processHeaders is the powerhouse method in the snapshot module. - -// It processes passed in headers, and updates the snapshot / snapshot store -func (i *backendIBFT) processHeaders(headers []*types.Header) error { - if len(headers) == 0 { - return nil - } - - parentSnap := i.getSnapshot(headers[0].Number - 1) - if parentSnap == nil { - return errParentSnapshotNotFound - } - - snap := parentSnap.Copy() - - // saveSnap is a callback function to set height and hash in current snapshot with given header - // and store the snapshot to snapshot store - saveSnap := func(h *types.Header) { - snap.Number = h.Number - snap.Hash = h.Hash.String() - i.store.add(snap) - - // use saved snapshot as new parent and clone it for next - parentSnap = snap - snap = parentSnap.Copy() - } - - for _, h := range headers { - proposer, err := ecrecoverProposer(h) - if err != nil { - return err - } - - // Check if the recovered proposer is part of the validator set - if !snap.Set.Includes(proposer) { - return fmt.Errorf("unauthorized proposer") - } - - if hookErr := i.runHook( - ProcessHeadersHook, - h.Number, - &processHeadersHookParams{ - header: h, - snap: snap, - parentSnap: parentSnap, - proposer: proposer, - saveSnap: saveSnap, - }); hookErr != nil { - return hookErr - } - - if !snap.Equal(parentSnap) { - saveSnap(h) - } - } - - // update the metadata - i.store.updateLastBlock(headers[len(headers)-1].Number) - - return nil -} - -// getSnapshotMetadata returns the latest snapshot metadata -func (i *backendIBFT) getSnapshotMetadata() *snapshotMetadata { - meta := &snapshotMetadata{ - LastBlock: i.store.getLastBlock(), - } - - return meta -} - -// getSnapshot returns the snapshot at the specified block height -func (i *backendIBFT) getSnapshot(num uint64) *Snapshot { - // get it from the snapshot first - raw, ok := i.store.cache.Get(num) - if ok { - snap, _ := raw.(*Snapshot) - - return snap - } - - // find it in the store - snap := i.store.find(num) - - if snap != nil { - // add it to cache for future reference if found - i.store.cache.Add(snap.Number, snap) - } - - return snap -} - -// Vote defines the vote structure -type Vote struct { - Validator types.Address - Address types.Address - Authorize bool -} - -// Equal checks if two votes are equal -func (v *Vote) Equal(vv *Vote) bool { - if v.Validator != vv.Validator { - return false - } - - if v.Address != vv.Address { - return false - } - - if v.Authorize != vv.Authorize { - return false - } - - return true -} - -// Copy makes a copy of the vote, and returns it -func (v *Vote) Copy() *Vote { - vv := new(Vote) - *vv = *v - - return vv -} - -// Snapshot is the current state at a given point in time for validators and votes -type Snapshot struct { - // block number when the snapshot was created - Number uint64 - - // block hash when the snapshot was created - Hash string - - // votes casted in chronological order - Votes []*Vote - - // current set of validators - Set ValidatorSet -} - -// snapshotMetadata defines the metadata for the snapshot -type snapshotMetadata struct { - // LastBlock represents the latest block in the snapshot - LastBlock uint64 -} - -// Equal checks if two snapshots are equal -func (s *Snapshot) Equal(ss *Snapshot) bool { - // we only check if Votes and Set are equal since Number and Hash - // are only meant to be used for indexing - if len(s.Votes) != len(ss.Votes) { - return false - } - - for indx := range s.Votes { - if !s.Votes[indx].Equal(ss.Votes[indx]) { - return false - } - } - - return s.Set.Equal(&ss.Set) -} - -// Count returns the vote tally. -// The count increases if the callback function returns true -func (s *Snapshot) Count(h func(v *Vote) bool) (count int) { - for _, v := range s.Votes { - if h(v) { - count++ - } - } - - return -} - -// RemoveVotes removes votes from the snapshot, based on the passed in callback -func (s *Snapshot) RemoveVotes(h func(v *Vote) bool) { - for i := 0; i < len(s.Votes); i++ { - if h(s.Votes[i]) { - s.Votes = append(s.Votes[:i], s.Votes[i+1:]...) - i-- - } - } -} - -// Copy makes a copy of the snapshot -func (s *Snapshot) Copy() *Snapshot { - // Do not need to copy Number and Hash - ss := &Snapshot{ - Votes: make([]*Vote, len(s.Votes)), - Set: ValidatorSet{}, - } - - for indx, vote := range s.Votes { - ss.Votes[indx] = vote.Copy() - } - - ss.Set = append(ss.Set, s.Set...) - - return ss -} - -// ToProto converts the snapshot to a Proto snapshot -func (s *Snapshot) ToProto() *proto.Snapshot { - resp := &proto.Snapshot{ - Validators: []*proto.Snapshot_Validator{}, - Votes: []*proto.Snapshot_Vote{}, - Number: s.Number, - Hash: s.Hash, - } - - // add votes - for _, vote := range s.Votes { - resp.Votes = append(resp.Votes, &proto.Snapshot_Vote{ - Validator: vote.Validator.String(), - Proposed: vote.Address.String(), - Auth: vote.Authorize, - }) - } - - // add addresses - for _, val := range s.Set { - resp.Validators = append(resp.Validators, &proto.Snapshot_Validator{ - Address: val.String(), - }) - } - - return resp -} - -// snapshotStore defines the structure of the stored snapshots -type snapshotStore struct { - // lastNumber is the latest block number stored - lastNumber uint64 - - // lock is the snapshotStore mutex - lock sync.Mutex - - // list represents the actual snapshot sorted list - list snapshotSortedList - - cache *lru.Cache -} - -// newSnapshotStore returns a new snapshot store -func newSnapshotStore() *snapshotStore { - cache, err := lru.New(100) - if err != nil { - return nil - } - - return &snapshotStore{ - cache: cache, - list: snapshotSortedList{}, - } -} - -// loadFromPath loads a saved snapshot store from the specified file system path -func (s *snapshotStore) loadFromPath(path string, l hclog.Logger) error { - // Load metadata - var meta *snapshotMetadata - if err := readDataStore(filepath.Join(path, "metadata"), &meta); err != nil { - // if we can't read metadata file delete it - // and log the error that we've encountered - l.Error("Could not read metadata snapshot store file", "err", err.Error()) - os.Remove(filepath.Join(path, "metadata")) - l.Error("Removed invalid metadata snapshot store file") - } - - if meta != nil { - s.lastNumber = meta.LastBlock - } - - // Load snapshots - snaps := []*Snapshot{} - if err := readDataStore(filepath.Join(path, "snapshots"), &snaps); err != nil { - // if we can't read snapshot store file delete it - // and log the error that we've encountered - l.Error("Could not read snapshot store file", "err", err.Error()) - os.Remove(filepath.Join(path, "snapshots")) - l.Error("Removed invalid snapshot store file") - } - - for _, snap := range snaps { - s.add(snap) - } - - return nil -} - -// saveToPath saves the snapshot store as a file to the specified path -func (s *snapshotStore) saveToPath(path string) error { - // Write snapshots - if err := writeDataStore(filepath.Join(path, "snapshots"), s.list); err != nil { - return err - } - - // Write metadata - meta := &snapshotMetadata{ - LastBlock: s.lastNumber, - } - if err := writeDataStore(filepath.Join(path, "metadata"), meta); err != nil { - return err - } - - return nil -} - -// getLastBlock returns the latest block number from the snapshot store. [Thread safe] -func (s *snapshotStore) getLastBlock() uint64 { - return atomic.LoadUint64(&s.lastNumber) -} - -// updateLastBlock sets the latest block number in the snapshot store. [Thread safe] -func (s *snapshotStore) updateLastBlock(num uint64) { - atomic.StoreUint64(&s.lastNumber, num) -} - -// deleteLower deletes snapshots that have a block number lower than the passed in parameter -func (s *snapshotStore) deleteLower(num uint64) { - s.lock.Lock() - defer s.lock.Unlock() - - i := sort.Search(len(s.list), func(i int) bool { - return s.list[i].Number >= num - }) - s.list = s.list[i:] -} - -// find returns the index of the first closest snapshot to the number specified -func (s *snapshotStore) find(num uint64) *Snapshot { - s.lock.Lock() - defer s.lock.Unlock() - - if len(s.list) == 0 { - return nil - } - - // fast track, check the last item - if last := s.list[len(s.list)-1]; last.Number < num { - return last - } - - i := sort.Search(len(s.list), func(i int) bool { - return s.list[i].Number >= num - }) - - if i < len(s.list) { - if i == 0 { - return s.list[0] - } - - if s.list[i].Number == num { - return s.list[i] - } - - return s.list[i-1] - } - - return nil -} - -// add adds a new snapshot to the snapshot store -func (s *snapshotStore) add(snap *Snapshot) { - s.lock.Lock() - defer s.lock.Unlock() - - s.cache.Add(snap.Number, snap) - - // append and sort the list - s.list = append(s.list, snap) - sort.Sort(&s.list) -} - -func (s *snapshotStore) replace(snap *Snapshot) { - s.lock.Lock() - defer s.lock.Unlock() - - for i, sn := range s.list { - if sn.Number == snap.Number { - s.list[i] = snap - s.cache.Add(snap.Number, snap) - - return - } - } -} - -// snapshotSortedList defines the sorted snapshot list -type snapshotSortedList []*Snapshot - -// Len returns the size of the sorted snapshot list -func (s snapshotSortedList) Len() int { - return len(s) -} - -// Swap swaps two values in the sorted snapshot list -func (s snapshotSortedList) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less checks if the element at index I has a lower number than the element at index J -func (s snapshotSortedList) Less(i, j int) bool { - return s[i].Number < s[j].Number -} - -// readDataStore attempts to read the specific file from file storage -func readDataStore(path string, obj interface{}) error { - if _, err := os.Stat(path); os.IsNotExist(err) { - return nil - } - - data, err := ioutil.ReadFile(path) - if err != nil { - return err - } - - if err := json.Unmarshal(data, obj); err != nil { - return err - } - - return nil -} - -// writeDataStore attempts to write the specific file to file storage -func writeDataStore(path string, obj interface{}) error { - data, err := json.Marshal(obj) - if err != nil { - return err - } - - //nolint: gosec - if err := ioutil.WriteFile(path, data, 0755); err != nil { - return err - } - - return nil -} diff --git a/consensus/ibft/snapshot_test.go b/consensus/ibft/snapshot_test.go deleted file mode 100644 index 44a9932c36..0000000000 --- a/consensus/ibft/snapshot_test.go +++ /dev/null @@ -1,879 +0,0 @@ -package ibft - -import ( - "crypto/ecdsa" - "io/ioutil" - "os" - "strconv" - "testing" - - "github.com/0xPolygon/polygon-edge/consensus" - - "github.com/0xPolygon/polygon-edge/blockchain" - "github.com/0xPolygon/polygon-edge/chain" - "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/common" - "github.com/0xPolygon/polygon-edge/types" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/assert" -) - -// initIbftMechanism initializes the IBFT mechanism for unit tests -func initIbftMechanism(mechanismType MechanismType, ibft *backendIBFT) { - mechanismFactory := mechanismBackends[mechanismType] - mechanism, _ := mechanismFactory(ibft, &IBFTFork{ - Type: mechanismType, - From: common.JSONNumber{Value: 0}, - }) - ibft.mechanisms = []ConsensusMechanism{mechanism} -} - -func getTempDir(t *testing.T) string { - t.Helper() - - tmpDir, err := ioutil.TempDir("/tmp", "snapshot-store") - assert.NoError(t, err) - t.Cleanup(func() { - if err := os.RemoveAll(tmpDir); err != nil { - t.Error(err) - } - }) - - return tmpDir -} - -type testerAccount struct { - alias string - priv *ecdsa.PrivateKey -} - -func (t *testerAccount) Address() types.Address { - return crypto.PubKeyToAddress(&t.priv.PublicKey) -} - -func (t *testerAccount) sign(h *types.Header) *types.Header { - h, _ = writeProposerSeal(t.priv, h) - - return h -} - -type testerAccountPool struct { - accounts []*testerAccount -} - -func newTesterAccountPool(num ...int) *testerAccountPool { - t := &testerAccountPool{ - accounts: []*testerAccount{}, - } - - if len(num) == 1 { - for i := 0; i < num[0]; i++ { - key, _ := crypto.GenerateKey() - - t.accounts = append(t.accounts, &testerAccount{ - alias: strconv.Itoa(i), - priv: key, - }) - } - } - - return t -} - -func (ap *testerAccountPool) add(accounts ...string) { - for _, account := range accounts { - if acct := ap.get(account); acct != nil { - continue - } - - priv, err := crypto.GenerateKey() - if err != nil { - panic("BUG: Failed to generate crypto key") - } - - ap.accounts = append(ap.accounts, &testerAccount{ - alias: account, - priv: priv, - }) - } -} - -func (ap *testerAccountPool) genesis() *chain.Genesis { - genesis := &types.Header{ - MixHash: IstanbulDigest, - } - putIbftExtraValidators(genesis, ap.ValidatorSet()) - genesis.ComputeHash() - - c := &chain.Genesis{ - Mixhash: genesis.MixHash, - ExtraData: genesis.ExtraData, - } - - return c -} - -func (ap *testerAccountPool) get(name string) *testerAccount { - for _, i := range ap.accounts { - if i.alias == name { - return i - } - } - - return nil -} - -func (ap *testerAccountPool) ValidatorSet() ValidatorSet { - v := ValidatorSet{} - for _, i := range ap.accounts { - v = append(v, i.Address()) - } - - return v -} - -type mockVote struct { - validator string - candidate string - auth bool -} - -func skipVote(validator string) mockVote { - return mockVote{validator: validator} -} - -func vote(validator, candidate string, auth bool) mockVote { - return mockVote{ - validator: validator, - candidate: candidate, - auth: auth, - } -} - -type mockSnapshot struct { - validators []string - votes []mockVote -} - -type mockHeader struct { - action mockVote - snapshot *mockSnapshot -} - -func newMockHeader(validators []string, vote mockVote) mockHeader { - return mockHeader{ - action: vote, - snapshot: &mockSnapshot{ - validators: validators, - votes: []mockVote{}, - }, - } -} - -func buildHeaders(pool *testerAccountPool, genesis *chain.Genesis, mockHeaders []mockHeader) []*types.Header { - headers := make([]*types.Header, 0, len(mockHeaders)) - parentHash := genesis.Hash() - - for num, header := range mockHeaders { - v := header.action - pool.add(v.validator) - - h := &types.Header{ - Number: uint64(num + 1), - ParentHash: parentHash, - Miner: types.ZeroAddress, - MixHash: IstanbulDigest, - ExtraData: genesis.ExtraData, - } - - if v.candidate != "" { - // if candidate is empty, we are just creating a new block - // without votes - pool.add(v.candidate) - h.Miner = pool.get(v.candidate).Address() - } - - if v.auth { - // add auth to the vote - h.Nonce = nonceAuthVote - } else { - h.Nonce = nonceDropVote - } - - // sign the vote - h = pool.get(v.validator).sign(h) - h.ComputeHash() - - parentHash = h.Hash - headers = append(headers, h) - } - - return headers -} - -func updateHashesInSnapshots(t *testing.T, b *blockchain.Blockchain, snapshots []*Snapshot) { - t.Helper() - - for _, s := range snapshots { - hash := b.GetHashByNumber(s.Number) - assert.NotNil(t, hash) - s.Hash = hash.String() - } -} - -func saveSnapshots(t *testing.T, path string, snapshots []*Snapshot) { - t.Helper() - - if snapshots == nil { - return - } - - store := newSnapshotStore() - for _, snap := range snapshots { - store.add(snap) - } - - err := store.saveToPath(path) - - assert.NoError(t, err) -} - -func TestSnapshot_setupSnapshot(t *testing.T) { - // Current validators - validators := []string{"A", "B", "C", "D"} - // New voted validators - candidateValidators := []string{"E", "F"} - - pool := newTesterAccountPool() - pool.add(validators...) - validatorSet := pool.ValidatorSet() - genesis := pool.genesis() - - pool.add(candidateValidators...) - - newSnapshot := func(n uint64, set ValidatorSet, votes []*Vote) *Snapshot { - return &Snapshot{ - Number: n, - Set: set, - Votes: votes, - } - } - - type snapshotData struct { - LastBlock uint64 - Snapshots []*Snapshot - } - - var cases = []struct { - name string - epochSize uint64 - headers []mockHeader - savedSnapshots []*Snapshot - expectedResult snapshotData - }{ - { - name: "should create genesis", - headers: []mockHeader{}, - expectedResult: snapshotData{ - LastBlock: 0, - Snapshots: []*Snapshot{ - newSnapshot(0, validatorSet, []*Vote{}), - }, - }, - }, - { - name: "should load from file and advance to latest height without any update if they are in same epoch", - headers: []mockHeader{ - newMockHeader(validators, skipVote("A")), - newMockHeader(validators, skipVote("B")), - }, - savedSnapshots: []*Snapshot{ - newSnapshot(0, validatorSet, []*Vote{}), - }, - expectedResult: snapshotData{ - LastBlock: 2, - Snapshots: []*Snapshot{ - newSnapshot(0, validatorSet, []*Vote{}), - }, - }, - }, - { - name: "should generate snapshot from genesis because of no snapshot file", - headers: []mockHeader{ - newMockHeader(validators, skipVote("A")), - newMockHeader(validators, skipVote("B")), - }, - savedSnapshots: nil, - expectedResult: snapshotData{ - LastBlock: 2, - Snapshots: []*Snapshot{ - newSnapshot(0, validatorSet, []*Vote{}), - }, - }, - }, - { - name: "should generate snapshot from beginning of current epoch because of no snapshot file", - epochSize: 3, - headers: []mockHeader{ - newMockHeader(validators, skipVote("A")), - newMockHeader(validators, skipVote("B")), - newMockHeader(validators, skipVote("C")), - newMockHeader(validators, skipVote("D")), - }, - savedSnapshots: nil, - expectedResult: snapshotData{ - LastBlock: 4, - Snapshots: []*Snapshot{ - newSnapshot(3, validatorSet, []*Vote{}), - }, - }, - }, - { - name: "should recover votes from the beginning of current epoch", - epochSize: 3, - headers: []mockHeader{ - newMockHeader(validators, skipVote("A")), - newMockHeader(validators, vote("B", "F", true)), - newMockHeader(validators, skipVote("C")), - newMockHeader(validators, vote("D", "E", true)), - }, - savedSnapshots: nil, - expectedResult: snapshotData{ - LastBlock: 4, - Snapshots: []*Snapshot{ - newSnapshot(3, validatorSet, []*Vote{}), - newSnapshot(4, validatorSet, []*Vote{{ - Validator: pool.get("D").Address(), - Address: pool.get("E").Address(), - Authorize: true, - }}), - }, - }, - }, - { - name: "should not count votes from the beginning of current epoch as there cannot be any proposals " + - "during the checkpoint block", - epochSize: 3, - headers: []mockHeader{ - newMockHeader(validators, skipVote("A")), - newMockHeader(validators, vote("B", "F", true)), - newMockHeader(validators, skipVote("C")), - newMockHeader(validators, vote("D", "E", true)), - newMockHeader(validators, skipVote("D")), - newMockHeader(validators, vote("C", "F", true)), - newMockHeader(validators, vote("A", "F", true)), - }, - savedSnapshots: nil, - expectedResult: snapshotData{ - LastBlock: 7, - Snapshots: []*Snapshot{ - newSnapshot(6, validatorSet, []*Vote{}), - newSnapshot(7, validatorSet, []*Vote{{ - Validator: pool.get("A").Address(), - Address: pool.get("F").Address(), - Authorize: true, - }}), - }, - }, - }, - } - - for _, c := range cases { - epochSize := c.epochSize - if epochSize == 0 { - epochSize = 10 - } - - t.Run(c.name, func(t *testing.T) { - tmpDir := getTempDir(t) - // Build blockchain with headers - blockchain := blockchain.TestBlockchain(t, genesis) - initialHeaders := buildHeaders(pool, genesis, c.headers) - for _, h := range initialHeaders { - err := blockchain.WriteHeaders([]*types.Header{h}) - assert.NoError(t, err) - } - - ibft := &backendIBFT{ - epochSize: epochSize, - blockchain: blockchain, - config: &consensus.Config{ - Path: tmpDir, - }, - logger: hclog.NewNullLogger(), - } - - initIbftMechanism(PoA, ibft) - - // Write Hash to snapshots - updateHashesInSnapshots(t, blockchain, c.savedSnapshots) - updateHashesInSnapshots(t, blockchain, c.expectedResult.Snapshots) - saveSnapshots(t, tmpDir, c.savedSnapshots) - - assert.NoError(t, ibft.setupSnapshot()) - assert.Equal(t, c.expectedResult.LastBlock, ibft.store.getLastBlock()) - assert.Equal(t, c.expectedResult.Snapshots, ([]*Snapshot)(ibft.store.list)) - }) - } -} - -func TestSnapshot_ProcessHeaders(t *testing.T) { - var cases = []struct { - name string - epochSize uint64 - validators []string - headers []mockHeader - }{ - { - name: "single validator casts no vote", - validators: []string{ - "A", - }, - headers: []mockHeader{ - { - action: skipVote("A"), - snapshot: &mockSnapshot{ - validators: []string{"A"}, - }, - }, - }, - }, - { - name: "single validator votes to add two peers", - validators: []string{"A"}, - headers: []mockHeader{ - { - // one vote from A is enough to promote B. - // the vote is not even shown on the result - action: vote("A", "B", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - }, - }, - { - action: skipVote("B"), - }, - { - // one vote from A is NOT enough to promote C - // since now B is also a validator - action: vote("A", "C", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - votes: []mockVote{ - vote("A", "C", true), - }, - }, - }, - }, - }, - { - name: "single validator dropping himself", - validators: []string{"A"}, - headers: []mockHeader{ - { - action: vote("A", "A", false), - snapshot: &mockSnapshot{ - validators: []string{}, - }, - }, - }, - }, - { - name: "two validators, dropping requires consensus", - validators: []string{"A", "B"}, - headers: []mockHeader{ - { - action: vote("A", "B", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - votes: []mockVote{ - vote("A", "B", false), - }, - }, - }, - { - action: vote("B", "B", false), - snapshot: &mockSnapshot{ - validators: []string{"A"}, - }, - }, - }, - }, - { - name: "adding votes are only counted once per validator and target", - validators: []string{"A", "B"}, - headers: []mockHeader{ - { - action: vote("A", "C", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - votes: []mockVote{ - vote("A", "C", true), - }, - }, - }, - { - action: vote("A", "C", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - votes: []mockVote{ - vote("A", "C", true), - }, - }, - }, - }, - }, - { - name: "delete votes are only counted once per validator and target", - validators: []string{"A", "B", "C"}, - headers: []mockHeader{ - { - action: vote("A", "C", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "C", false), - }, - }, - }, - { - action: vote("A", "C", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "C", false), - }, - }, - }, - }, - }, - { - name: "multiple (add, delete) votes are possible", - validators: []string{"A", "B", "C"}, - headers: []mockHeader{ - { - action: vote("A", "D", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "D", true), - }, - }, - }, - { - action: vote("A", "E", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "D", true), - vote("A", "E", true), - }, - }, - }, - { - action: vote("A", "B", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "D", true), - vote("A", "E", true), - vote("A", "B", false), - }, - }, - }, - }, - }, - { - name: "votes from deauthorized nodes are discarded immediately", - validators: []string{"A", "B", "C"}, - headers: []mockHeader{ - // validator C makes two votes (add and delete) - { - action: vote("C", "D", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("C", "D", true), - }, - }, - }, - { - action: vote("C", "B", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("C", "D", true), - vote("C", "B", false), - }, - }, - }, - // A and B remove C - { - action: vote("A", "C", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("C", "D", true), - vote("C", "B", false), - vote("A", "C", false), - }, - }, - }, - // B vote is enough to discard C and clean all the votes - { - action: vote("B", "C", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B"}, - votes: []mockVote{}, - }, - }, - }, - }, - { - name: "epoch transition resets all votes", - epochSize: 3, - validators: []string{"A", "B", "C"}, - headers: []mockHeader{ - { - // block 1 - action: vote("A", "D", true), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "D", true), - }, - }, - }, - { - // block 2 - action: vote("B", "C", false), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{ - vote("A", "D", true), - vote("B", "C", false), - }, - }, - }, - { - // block 3 (do not vote) - action: skipVote("B"), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{}, - }, - }, - }, - }, - { - name: "epoch transition creates new snapshot", - epochSize: 1, - validators: []string{"A", "B", "C"}, - headers: []mockHeader{ - { - // block 1 - action: skipVote("A"), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{}, - }, - }, - { - // block 2 - action: skipVote("B"), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{}, - }, - }, - { - // block 3 - action: skipVote("C"), - snapshot: &mockSnapshot{ - validators: []string{"A", "B", "C"}, - votes: []mockVote{}, - }, - }, - }, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - epochSize := c.epochSize - if epochSize == 0 { - epochSize = 1000 - } - - pool := newTesterAccountPool() - pool.add(c.validators...) - genesis := pool.genesis() - - // create votes - headers := buildHeaders(pool, genesis, c.headers) - - // process the headers independently - ibft := &backendIBFT{ - epochSize: epochSize, - blockchain: blockchain.TestBlockchain(t, genesis), - config: &consensus.Config{}, - } - initIbftMechanism(PoA, ibft) - - assert.NoError(t, ibft.setupSnapshot()) - for indx, header := range headers { - if err := ibft.processHeaders([]*types.Header{header}); err != nil { - t.Fatal(err) - } - - // get latest snapshot - snap := ibft.getSnapshot(header.Number) - if snap == nil { - t.Fatalf("Unable to find snapshot") - } - assert.NotNil(t, snap) - - result := c.headers[indx].snapshot - if result != nil { - resSnap := &Snapshot{ - Votes: []*Vote{}, - Set: ValidatorSet{}, - } - // check validators - for _, i := range result.validators { - resSnap.Set.Add(pool.get(i).Address()) - } - // build result votes - for _, v := range result.votes { - resSnap.Votes = append(resSnap.Votes, &Vote{ - Validator: pool.get(v.validator).Address(), - Address: pool.get(v.candidate).Address(), - Authorize: v.auth, - }) - } - if !resSnap.Equal(snap) { - t.Fatal("bad") - } - } - } - - // check the metadata - meta := ibft.getSnapshotMetadata() - if meta == nil { - t.Fatal("Metadata not found") - } - - if meta.LastBlock != headers[len(headers)-1].Number { - t.Fatal("incorrect meta") - } - - // Process headers all at the same time should have the same result - ibft1 := &backendIBFT{ - epochSize: epochSize, - blockchain: blockchain.TestBlockchain(t, genesis), - config: &consensus.Config{}, - } - - initIbftMechanism(PoA, ibft1) - - assert.NoError(t, ibft1.setupSnapshot()) - if err := ibft1.processHeaders(headers); err != nil { - t.Fatal(err) - } - - // from 0 to last header check that all the snapshots match - for i := uint64(0); i < headers[len(headers)-1].Number; i++ { - snap0 := ibft.getSnapshot(i) - assert.NotNil(t, snap0) - - snap1 := ibft1.getSnapshot(i) - assert.NotNil(t, snap1) - - if !snap0.Equal(snap1) { - t.Fatal("bad") - } - } - }) - } -} - -func TestSnapshot_PurgeSnapshots(t *testing.T) { - pool := newTesterAccountPool() - pool.add("a", "b", "c") - - genesis := pool.genesis() - ibft1 := &backendIBFT{ - epochSize: 10, - blockchain: blockchain.TestBlockchain(t, genesis), - config: &consensus.Config{}, - } - assert.NoError(t, ibft1.setupSnapshot()) - initIbftMechanism(PoA, ibft1) - - // write a header that creates a snapshot - headers := []*types.Header{} - - for i := 1; i < 51; i++ { - id := strconv.Itoa(i) - pool.add(id) - - h := &types.Header{ - Number: uint64(i), - ParentHash: ibft1.blockchain.Header().Hash, - Miner: types.ZeroAddress, - MixHash: IstanbulDigest, - ExtraData: genesis.ExtraData, - } - - h.Miner = pool.get(id).Address() - h.Nonce = nonceAuthVote - - h = pool.get("a").sign(h) - h.ComputeHash() - headers = append(headers, h) - } - - err := ibft1.processHeaders(headers) - assert.NoError(t, err) - - assert.Equal(t, len(ibft1.store.list), 21) -} - -func TestSnapshot_Store_SaveLoad(t *testing.T) { - tmpDir := getTempDir(t) - store0 := newSnapshotStore() - - for i := 0; i < 10; i++ { - store0.add(&Snapshot{ - Number: uint64(i), - }) - } - assert.NoError(t, store0.saveToPath(tmpDir)) - - store1 := newSnapshotStore() - assert.NoError(t, store1.loadFromPath(tmpDir, hclog.NewNullLogger())) - - assert.Equal(t, store0, store1) -} - -func TestSnapshot_Store_Find(t *testing.T) { - store := newSnapshotStore() - - for i := 0; i <= 100; i++ { - if i%10 == 0 { - store.add(&Snapshot{ - Number: uint64(i), - }) - } - } - - check := func(num, expected uint64) { - assert.Equal(t, store.find(num).Number, expected) - } - - check(0, 0) - check(19, 10) - check(20, 20) - check(21, 20) - check(1000, 100) -} diff --git a/consensus/ibft/state.go b/consensus/ibft/state.go deleted file mode 100644 index bfd1a510c5..0000000000 --- a/consensus/ibft/state.go +++ /dev/null @@ -1,122 +0,0 @@ -package ibft - -import ( - "math" - - "github.com/0xPolygon/polygon-edge/types" -) - -type ValidatorSet []types.Address - -// CalcProposer calculates the address of the next proposer, from the validator set -func (v *ValidatorSet) CalcProposer(round uint64, lastProposer types.Address) types.Address { - var seed uint64 - - if lastProposer == types.ZeroAddress { - seed = round - } else { - offset := 0 - if indx := v.Index(lastProposer); indx != -1 { - offset = indx - } - - seed = uint64(offset) + round + 1 - } - - pick := seed % uint64(v.Len()) - - return (*v)[pick] -} - -// Add adds a new address to the validator set -func (v *ValidatorSet) Add(addr types.Address) { - *v = append(*v, addr) -} - -// Del removes an address from the validator set -func (v *ValidatorSet) Del(addr types.Address) { - for indx, i := range *v { - if i == addr { - *v = append((*v)[:indx], (*v)[indx+1:]...) - } - } -} - -// Len returns the size of the validator set -func (v *ValidatorSet) Len() int { - return len(*v) -} - -// Equal checks if 2 validator sets are equal -func (v *ValidatorSet) Equal(vv *ValidatorSet) bool { - if len(*v) != len(*vv) { - return false - } - - for indx := range *v { - if (*v)[indx] != (*vv)[indx] { - return false - } - } - - return true -} - -// Index returns the index of the passed in address in the validator set. -// Returns -1 if not found -func (v *ValidatorSet) Index(addr types.Address) int { - for indx, i := range *v { - if i == addr { - return indx - } - } - - return -1 -} - -// Includes checks if the address is in the validator set -func (v *ValidatorSet) Includes(addr types.Address) bool { - return v.Index(addr) != -1 -} - -// MaxFaultyNodes returns the maximum number of allowed faulty nodes (F), based on the current validator set -func (v *ValidatorSet) MaxFaultyNodes() int { - // N -> number of nodes in IBFT - // F -> number of faulty nodes - // - // N = 3F + 1 - // => F = (N - 1) / 3 - // - // IBFT tolerates 1 failure with 4 nodes - // 4 = 3 * 1 + 1 - // To tolerate 2 failures, IBFT requires 7 nodes - // 7 = 3 * 2 + 1 - // It should always take the floor of the result - return (len(*v) - 1) / 3 -} - -type QuorumImplementation func(ValidatorSet) int - -// LegacyQuorumSize returns the legacy quorum size for the given validator set -func LegacyQuorumSize(set ValidatorSet) int { - // According to the IBFT spec, the number of valid messages - // needs to be 2F + 1 - return 2*set.MaxFaultyNodes() + 1 -} - -// OptimalQuorumSize returns the optimal quorum size for the given validator set -func OptimalQuorumSize(set ValidatorSet) int { - // if the number of validators is less than 4, - // then the entire set is required - if set.MaxFaultyNodes() == 0 { - /* - N: 1 -> Q: 1 - N: 2 -> Q: 2 - N: 3 -> Q: 3 - */ - return set.Len() - } - - // (quorum optimal) Q = ceil(2/3 * N) - return int(math.Ceil(2 * float64(set.Len()) / 3)) -} diff --git a/consensus/ibft/state_test.go b/consensus/ibft/state_test.go index 4b5c141c7f..db374e0466 100644 --- a/consensus/ibft/state_test.go +++ b/consensus/ibft/state_test.go @@ -22,9 +22,9 @@ func TestState_FaultyNodes(t *testing.T) { {9, 2}, } for _, c := range cases { - pool := newTesterAccountPool(int(c.Network)) + pool := newTesterAccountPool(t, int(c.Network)) vals := pool.ValidatorSet() - assert.Equal(t, vals.MaxFaultyNodes(), int(c.Faulty)) + assert.Equal(t, CalcMaxFaultyNodes(vals), int(c.Faulty)) } } @@ -56,7 +56,7 @@ func TestNumValid(t *testing.T) { } for _, c := range cases { - pool := newTesterAccountPool(int(c.Network)) + pool := newTesterAccountPool(t, int(c.Network)) addAccounts(pool, int(c.Network)) assert.Equal(t, diff --git a/consensus/ibft/validators.go b/consensus/ibft/validators.go new file mode 100644 index 0000000000..9c1a59a2f8 --- /dev/null +++ b/consensus/ibft/validators.go @@ -0,0 +1,73 @@ +package ibft + +import ( + "math" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +func CalcMaxFaultyNodes(s validators.Validators) int { + // N -> number of nodes in IBFT + // F -> number of faulty nodes + // + // N = 3F + 1 + // => F = (N - 1) / 3 + // + // IBFT tolerates 1 failure with 4 nodes + // 4 = 3 * 1 + 1 + // To tolerate 2 failures, IBFT requires 7 nodes + // 7 = 3 * 2 + 1 + // It should always take the floor of the result + return (s.Len() - 1) / 3 +} + +type QuorumImplementation func(validators.Validators) int + +// LegacyQuorumSize returns the legacy quorum size for the given validator set +func LegacyQuorumSize(set validators.Validators) int { + // According to the IBFT spec, the number of valid messages + // needs to be 2F + 1 + return 2*CalcMaxFaultyNodes(set) + 1 +} + +// OptimalQuorumSize returns the optimal quorum size for the given validator set +func OptimalQuorumSize(set validators.Validators) int { + // if the number of validators is less than 4, + // then the entire set is required + if CalcMaxFaultyNodes(set) == 0 { + /* + N: 1 -> Q: 1 + N: 2 -> Q: 2 + N: 3 -> Q: 3 + */ + return set.Len() + } + + // (quorum optimal) Q = ceil(2/3 * N) + return int(math.Ceil(2 * float64(set.Len()) / 3)) +} + +func CalcProposer( + validators validators.Validators, + round uint64, + lastProposer types.Address, +) validators.Validator { + var seed uint64 + + if lastProposer == types.ZeroAddress { + seed = round + } else { + offset := int64(0) + + if index := validators.Index(lastProposer); index != -1 { + offset = index + } + + seed = uint64(offset) + round + 1 + } + + pick := seed % uint64(validators.Len()) + + return validators.At(pick) +} diff --git a/consensus/ibft/verifier.go b/consensus/ibft/verifier.go index c00e69a7be..ab8348c8d5 100644 --- a/consensus/ibft/verifier.go +++ b/consensus/ibft/verifier.go @@ -2,8 +2,7 @@ package ibft import ( "bytes" - "errors" - "fmt" + "encoding/hex" "github.com/0xPolygon/go-ibft/messages" protoIBFT "github.com/0xPolygon/go-ibft/messages/proto" @@ -36,14 +35,14 @@ func (i *backendIBFT) IsValidBlock(proposal []byte) bool { return false } - snap := i.getSnapshot(latestBlockNumber) - if snap == nil { - i.logger.Error("snapshot not found", "num", latestBlockNumber) - - return false - } - - if err := i.verifyHeaderImpl(snap, latestHeader, newBlock.Header); err != nil { + if err := i.verifyHeaderImpl( + latestHeader, + newBlock.Header, + i.currentSigner, + i.currentValidators, + i.currentHooks, + true, + ); err != nil { i.logger.Error("block header verification failed", "err", err) return false @@ -55,13 +54,8 @@ func (i *backendIBFT) IsValidBlock(proposal []byte) bool { return false } - if err := i.runHook(VerifyBlockHook, newBlock.Number(), newBlock); err != nil { - //nolint:govet - if errors.As(err, &errBlockVerificationFailed) { - i.logger.Error("block verification fail, block at the end of epoch has transactions") - } else { - i.logger.Error(fmt.Sprintf("Unable to run hook %s, %v", VerifyBlockHook, err)) - } + if err := i.currentHooks.VerifyBlock(newBlock); err != nil { + i.logger.Error("additional block verification failed", "err", err) return false } @@ -75,21 +69,45 @@ func (i *backendIBFT) IsValidSender(msg *protoIBFT.Message) bool { return false } - validatorAddress, err := ecrecoverImpl( + signerAddress, err := i.currentSigner.EcrecoverFromIBFTMessage( msg.Signature, msgNoSig, ) + if err != nil { + i.logger.Error("failed to ecrecover message", "err", err) + return false } // verify the signature came from the sender - if !bytes.Equal(msg.From, validatorAddress.Bytes()) { + if !bytes.Equal(msg.From, signerAddress.Bytes()) { + i.logger.Error( + "signer address doesn't match with From", + "from", hex.EncodeToString(msg.From), + "signer", signerAddress, + "err", err, + ) + + return false + } + + validators, err := i.forkManager.GetValidators(msg.View.Height) + if err != nil { return false } // verify the sender is in the active validator set - return i.activeValidatorSet.Includes(validatorAddress) + if !validators.Includes(signerAddress) { + i.logger.Error( + "signer address doesn't included in validators", + "signer", signerAddress, + ) + + return false + } + + return true } func (i *backendIBFT) IsProposer(id []byte, height, round uint64) bool { @@ -100,9 +118,20 @@ func (i *backendIBFT) IsProposer(id []byte, height, round uint64) bool { return false } - nextProposer := i.activeValidatorSet.CalcProposer(round, extractProposer(previousHeader)) + previousProposer, err := i.extractProposer(previousHeader) + if err != nil { + i.logger.Error("failed to extract the last proposer", "height", height-1, "err", err) + + return false + } + + nextProposer := CalcProposer( + i.currentValidators, + round, + previousProposer, + ) - return bytes.Equal(nextProposer.Bytes(), id) + return types.BytesToAddress(id) == nextProposer.Addr() } func (i *backendIBFT) IsValidProposalHash(proposal, hash []byte) bool { @@ -122,22 +151,15 @@ func (i *backendIBFT) IsValidCommittedSeal( proposalHash []byte, committedSeal *messages.CommittedSeal, ) bool { - // seal was generated based on the proposal hash - signer, err := ecrecoverImpl(committedSeal.Signature, wrapCommitHash(proposalHash)) - if err != nil { - i.logger.Error("unable to recover seal", "err", err) - - return false - } - - if signer != types.BytesToAddress(committedSeal.Signer) { - i.logger.Error("mismatch between signer and message sender", "err", err) - - return false - } + err := i.currentSigner.VerifyCommittedSeal( + i.currentValidators, + types.BytesToAddress(committedSeal.Signer), + committedSeal.Signature, + proposalHash, + ) - if !i.activeValidatorSet.Includes(signer) { - i.logger.Error("seal generated by validator not in the active set", "validator", signer.String()) + if err != nil { + i.logger.Error("IsValidCommittedSeal: failed to verify committed seal", "err", err) return false } @@ -145,14 +167,20 @@ func (i *backendIBFT) IsValidCommittedSeal( return true } -// helpers - -func extractProposer(header *types.Header) types.Address { +func (i *backendIBFT) extractProposer(header *types.Header) (types.Address, error) { if header.Number == 0 { - return types.Address{} + return types.ZeroAddress, nil } - proposer, _ := ecrecoverProposer(header) + signer, err := i.forkManager.GetSigner(header.Number) + if err != nil { + return types.ZeroAddress, err + } + + proposer, err := signer.EcrecoverFromHeader(header) + if err != nil { + return types.ZeroAddress, err + } - return proposer + return proposer, nil } diff --git a/contracts/abis/abis.go b/contracts/abis/abis.go index 32e03c3758..dfc285c8b1 100644 --- a/contracts/abis/abis.go +++ b/contracts/abis/abis.go @@ -4,5 +4,10 @@ import ( "github.com/umbracle/ethgo/abi" ) -var StakingABI = abi.MustNewABI(StakingJSONABI) -var StressTestABI = abi.MustNewABI(StressTestJSONABI) +var ( + // ABI for Staking Contract + StakingABI = abi.MustNewABI(StakingJSONABI) + + // ABI for Contract used in e2e stress test + StressTestABI = abi.MustNewABI(StressTestJSONABI) +) diff --git a/contracts/abis/json.go b/contracts/abis/json.go index fde24f5a0a..88cb4b0d9d 100644 --- a/contracts/abis/json.go +++ b/contracts/abis/json.go @@ -2,7 +2,18 @@ package abis const StakingJSONABI = `[ { - "inputs": [], + "inputs": [ + { + "internalType": "uint256", + "name": "minNumValidators", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxNumValidators", + "type": "uint256" + } + ], "stateMutability": "nonpayable", "type": "constructor" }, @@ -46,7 +57,7 @@ const StakingJSONABI = `[ }, { "inputs": [], - "name": "ValidatorThreshold", + "name": "VALIDATOR_THRESHOLD", "outputs": [ { "internalType": "uint128", @@ -57,6 +68,121 @@ const StakingJSONABI = `[ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "_addressToBLSPublicKey", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "_addressToIsValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "_addressToStakedAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "_addressToValidatorIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_maximumNumValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_minimumNumValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stakedAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -76,6 +202,83 @@ const StakingJSONABI = `[ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "accountStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "isValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maximumNumValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minimumNumValidators", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "blsPubKey", + "type": "bytes" + } + ], + "name": "registerBLSPublicKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "stake", @@ -103,6 +306,19 @@ const StakingJSONABI = `[ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "validatorBLSPublicKeys", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "validators", @@ -115,8 +331,13 @@ const StakingJSONABI = `[ ], "stateMutability": "view", "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" } ]` + const StressTestJSONABI = `[ { "inputs": [], diff --git a/contracts/staking/query.go b/contracts/staking/query.go index c14d819403..4bf285dbb7 100644 --- a/contracts/staking/query.go +++ b/contracts/staking/query.go @@ -12,14 +12,65 @@ import ( "github.com/umbracle/ethgo/abi" ) +const ( + methodValidators = "validators" + methodValidatorBLSPublicKeys = "validatorBLSPublicKeys" +) + var ( // staking contract address AddrStakingContract = types.StringToAddress("1001") // Gas limit used when querying the validator set queryGasLimit uint64 = 100000 + + ErrMethodNotFoundInABI = errors.New("method not found in ABI") + ErrFailedTypeAssertion = errors.New("failed type assertion") ) +// TxQueryHandler is a interface to call view method in the contract +type TxQueryHandler interface { + Apply(*types.Transaction) (*runtime.ExecutionResult, error) + GetNonce(types.Address) uint64 +} + +// decodeWeb3ArrayOfBytes is a helper function to parse the data +// representing array of bytes in contract result +func decodeWeb3ArrayOfBytes( + result interface{}, +) ([][]byte, error) { + mapResult, ok := result.(map[string]interface{}) + if !ok { + return nil, ErrFailedTypeAssertion + } + + bytesArray, ok := mapResult["0"].([][]byte) + if !ok { + return nil, ErrFailedTypeAssertion + } + + return bytesArray, nil +} + +// createCallViewTx is a helper function to create a transaction to call view method +func createCallViewTx( + from types.Address, + contractAddress types.Address, + methodID []byte, + nonce uint64, +) *types.Transaction { + return &types.Transaction{ + From: from, + To: &contractAddress, + Input: methodID, + Nonce: nonce, + Gas: queryGasLimit, + Value: big.NewInt(0), + GasPrice: big.NewInt(0), + } +} + +// DecodeValidators parses contract call result and returns array of address func DecodeValidators(method *abi.Method, returnValue []byte) ([]types.Address, error) { decodedResults, err := method.Outputs.Decode(returnValue) if err != nil { @@ -45,27 +96,19 @@ func DecodeValidators(method *abi.Method, returnValue []byte) ([]types.Address, return addresses, nil } -type TxQueryHandler interface { - Apply(*types.Transaction) (*runtime.ExecutionResult, error) - GetNonce(types.Address) uint64 -} - +// QueryValidators is a helper function to get validator addresses from contract func QueryValidators(t TxQueryHandler, from types.Address) ([]types.Address, error) { - method, ok := abis.StakingABI.Methods["validators"] + method, ok := abis.StakingABI.Methods[methodValidators] if !ok { - return nil, errors.New("validators method doesn't exist in Staking contract ABI") + return nil, ErrMethodNotFoundInABI } - selector := method.ID() - res, err := t.Apply(&types.Transaction{ - From: from, - To: &AddrStakingContract, - Value: big.NewInt(0), - Input: selector, - GasPrice: big.NewInt(0), - Gas: queryGasLimit, - Nonce: t.GetNonce(from), - }) + res, err := t.Apply(createCallViewTx( + from, + AddrStakingContract, + method.ID(), + t.GetNonce(from), + )) if err != nil { return nil, err @@ -77,3 +120,46 @@ func QueryValidators(t TxQueryHandler, from types.Address) ([]types.Address, err return DecodeValidators(method, res.ReturnValue) } + +// decodeBLSPublicKeys parses contract call result and returns array of bytes +func decodeBLSPublicKeys( + method *abi.Method, + returnValue []byte, +) ([][]byte, error) { + decodedResults, err := method.Outputs.Decode(returnValue) + if err != nil { + return nil, err + } + + blsPublicKeys, err := decodeWeb3ArrayOfBytes(decodedResults) + if err != nil { + return nil, err + } + + return blsPublicKeys, nil +} + +// QueryBLSPublicKeys is a helper function to get BLS Public Keys from contract +func QueryBLSPublicKeys(t TxQueryHandler, from types.Address) ([][]byte, error) { + method, ok := abis.StakingABI.Methods[methodValidatorBLSPublicKeys] + if !ok { + return nil, ErrMethodNotFoundInABI + } + + res, err := t.Apply(createCallViewTx( + from, + AddrStakingContract, + method.ID(), + t.GetNonce(from), + )) + + if err != nil { + return nil, err + } + + if res.Failed() { + return nil, res.Err + } + + return decodeBLSPublicKeys(method, res.ReturnValue) +} diff --git a/crypto/crypto.go b/crypto/crypto.go index 5ef2ea223d..00dab6c48d 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -15,9 +15,9 @@ import ( "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/types" "github.com/btcsuite/btcd/btcec" - "golang.org/x/crypto/sha3" - + "github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig" "github.com/umbracle/fastrlp" + "golang.org/x/crypto/sha3" ) var ( @@ -30,6 +30,15 @@ var S256 = btcec.S256() var ( secp256k1N = hex.MustDecodeHex("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") one = []byte{0x01} + + ErrInvalidBLSSignature = errors.New("invalid BLS Signature") +) + +type KeyType string + +const ( + KeyECDSA KeyType = "ecdsa" + KeyBLS KeyType = "bls" ) var ( @@ -99,19 +108,19 @@ func CreateAddress2(addr types.Address, salt [32]byte, inithash []byte) types.Ad return types.BytesToAddress(Keccak256(create2Prefix, addr.Bytes(), salt[:], Keccak256(inithash))[12:]) } -func ParsePrivateKey(buf []byte) (*ecdsa.PrivateKey, error) { +func ParseECDSAPrivateKey(buf []byte) (*ecdsa.PrivateKey, error) { prv, _ := btcec.PrivKeyFromBytes(S256, buf) return prv.ToECDSA(), nil } -// MarshalPrivateKey serializes the private key's D value to a []byte -func MarshalPrivateKey(priv *ecdsa.PrivateKey) ([]byte, error) { +// MarshalECDSAPrivateKey serializes the private key's D value to a []byte +func MarshalECDSAPrivateKey(priv *ecdsa.PrivateKey) ([]byte, error) { return (*btcec.PrivateKey)(priv).Serialize(), nil } -// GenerateKey generates a new key based on the secp256k1 elliptic curve. -func GenerateKey() (*ecdsa.PrivateKey, error) { +// GenerateECDSAKey generates a new key based on the secp256k1 elliptic curve. +func GenerateECDSAKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(S256, rand.Reader) } @@ -180,6 +189,45 @@ func Sign(priv *ecdsa.PrivateKey, hash []byte) ([]byte, error) { return append(sig, term)[1:], nil } +// SignByBLS signs the given data by BLS +func SignByBLS(prv *bls_sig.SecretKey, msg []byte) ([]byte, error) { + signature, err := bls_sig.NewSigPop().Sign(prv, msg) + if err != nil { + return nil, err + } + + return signature.MarshalBinary() +} + +// VerifyBLSSignature verifies the given signature from Public Key and original message +func VerifyBLSSignature(pubkey *bls_sig.PublicKey, sig *bls_sig.Signature, message []byte) error { + ok, err := bls_sig.NewSigPop().Verify(pubkey, message, sig) + if err != nil { + return err + } + + if !ok { + return ErrInvalidBLSSignature + } + + return nil +} + +// VerifyBLSSignatureFromBytes verifies BLS Signature from BLS PublicKey, signature, and original message in bytes +func VerifyBLSSignatureFromBytes(rawPubkey, rawSig, message []byte) error { + pubkey, err := UnmarshalBLSPublicKey(rawPubkey) + if err != nil { + return err + } + + signature, err := UnmarshalBLSSignature(rawSig) + if err != nil { + return err + } + + return VerifyBLSSignature(pubkey, signature, message) +} + // SigToPub returns the public key that created the given signature. func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { s, err := Ecrecover(hash, sig) @@ -221,14 +269,14 @@ func GetAddressFromKey(key goCrypto.PrivateKey) (types.Address, error) { return PubKeyToAddress(&publicKey), nil } -// generateKeyAndMarshal generates a new private key and serializes it to a byte array -func generateKeyAndMarshal() ([]byte, error) { - key, err := GenerateKey() +// generateECDSAKeyAndMarshal generates a new ECDSA private key and serializes it to a byte array +func generateECDSAKeyAndMarshal() ([]byte, error) { + key, err := GenerateECDSAKey() if err != nil { return nil, err } - buf, err := MarshalPrivateKey(key) + buf, err := MarshalECDSAPrivateKey(key) if err != nil { return nil, err } @@ -236,8 +284,8 @@ func generateKeyAndMarshal() ([]byte, error) { return buf, nil } -// BytesToPrivateKey reads the input byte array and constructs a private key if possible -func BytesToPrivateKey(input []byte) (*ecdsa.PrivateKey, error) { +// BytesToECDSAPrivateKey reads the input byte array and constructs a private key if possible +func BytesToECDSAPrivateKey(input []byte) (*ecdsa.PrivateKey, error) { // The key file on disk should be encoded in Base64, // so it must be decoded before it can be parsed by ParsePrivateKey decoded, err := hex.DecodeString(string(input)) @@ -252,7 +300,7 @@ func BytesToPrivateKey(input []byte) (*ecdsa.PrivateKey, error) { } // Convert decoded bytes to a private key - key, err := ParsePrivateKey(decoded) + key, err := ParseECDSAPrivateKey(decoded) if err != nil { return nil, err } @@ -260,15 +308,106 @@ func BytesToPrivateKey(input []byte) (*ecdsa.PrivateKey, error) { return key, nil } +// GenerateBLSKey generates a new BLS key +func GenerateBLSKey() (*bls_sig.SecretKey, error) { + blsPop := bls_sig.NewSigPop() + + _, sk, err := blsPop.Keygen() + if err != nil { + return nil, err + } + + return sk, nil +} + +// generateBLSKeyAndMarshal generates a new BLS secret key and serializes it to a byte array +func generateBLSKeyAndMarshal() ([]byte, error) { + key, err := GenerateBLSKey() + if err != nil { + return nil, err + } + + buf, err := key.MarshalBinary() + if err != nil { + return nil, err + } + + return buf, nil +} + +// BytesToECDSAPrivateKey reads the input byte array and constructs a private key if possible +func BytesToBLSSecretKey(input []byte) (*bls_sig.SecretKey, error) { + // The key file on disk should be encoded in Base64, + // so it must be decoded before it can be parsed by ParsePrivateKey + decoded, err := hex.DecodeString(string(input)) + if err != nil { + return nil, err + } + + sk := &bls_sig.SecretKey{} + if err := sk.UnmarshalBinary(decoded); err != nil { + return nil, err + } + + return sk, nil +} + +// BLSSecretKeyToPubkeyBytes returns bytes of BLS Public Key corresponding to the given secret key +func BLSSecretKeyToPubkeyBytes(key *bls_sig.SecretKey) ([]byte, error) { + pubKey, err := key.GetPublicKey() + if err != nil { + return nil, err + } + + marshalled, err := pubKey.MarshalBinary() + if err != nil { + return nil, err + } + + return marshalled, nil +} + +// BytesToBLSPublicKey decodes given hex string and returns BLS Public Key +func BytesToBLSPublicKey(input string) (*bls_sig.PublicKey, error) { + // The key file on disk should be encoded in Base64, + // so it must be decoded before it can be parsed by ParsePrivateKey + decoded, err := hex.DecodeString(input) + if err != nil { + return nil, err + } + + return UnmarshalBLSPublicKey(decoded) +} + +// UnmarshalBLSPublicKey unmarshal bytes data into BLS Public Key +func UnmarshalBLSPublicKey(input []byte) (*bls_sig.PublicKey, error) { + pk := &bls_sig.PublicKey{} + if err := pk.UnmarshalBinary(input); err != nil { + return nil, err + } + + return pk, nil +} + +// UnmarshalBLSSignature unmarshal bytes data into BLS Signature +func UnmarshalBLSSignature(input []byte) (*bls_sig.Signature, error) { + sig := &bls_sig.Signature{} + if err := sig.UnmarshalBinary(input); err != nil { + return nil, err + } + + return sig, nil +} + // GenerateOrReadPrivateKey generates a private key at the specified path, // or reads it if a key file is present func GenerateOrReadPrivateKey(path string) (*ecdsa.PrivateKey, error) { - keyBuff, err := keystore.CreateIfNotExists(path, generateKeyAndMarshal) + keyBuff, err := keystore.CreateIfNotExists(path, generateECDSAKeyAndMarshal) if err != nil { return nil, err } - privateKey, err := BytesToPrivateKey(keyBuff) + privateKey, err := BytesToECDSAPrivateKey(keyBuff) if err != nil { return nil, fmt.Errorf("unable to execute byte array -> private key conversion, %w", err) } @@ -276,14 +415,14 @@ func GenerateOrReadPrivateKey(path string) (*ecdsa.PrivateKey, error) { return privateKey, nil } -// GenerateAndEncodePrivateKey returns a newly generated private key and the Base64 encoding of that private key -func GenerateAndEncodePrivateKey() (*ecdsa.PrivateKey, []byte, error) { - keyBuff, err := keystore.CreatePrivateKey(generateKeyAndMarshal) +// GenerateAndEncodeECDSAPrivateKey returns a newly generated private key and the Base64 encoding of that private key +func GenerateAndEncodeECDSAPrivateKey() (*ecdsa.PrivateKey, []byte, error) { + keyBuff, err := keystore.CreatePrivateKey(generateECDSAKeyAndMarshal) if err != nil { return nil, nil, err } - privateKey, err := BytesToPrivateKey(keyBuff) + privateKey, err := BytesToECDSAPrivateKey(keyBuff) if err != nil { return nil, nil, fmt.Errorf("unable to execute byte array -> private key conversion, %w", err) } @@ -291,11 +430,25 @@ func GenerateAndEncodePrivateKey() (*ecdsa.PrivateKey, []byte, error) { return privateKey, keyBuff, nil } +func GenerateAndEncodeBLSSecretKey() (*bls_sig.SecretKey, []byte, error) { + keyBuff, err := keystore.CreatePrivateKey(generateBLSKeyAndMarshal) + if err != nil { + return nil, nil, err + } + + secretKey, err := BytesToBLSSecretKey(keyBuff) + if err != nil { + return nil, nil, fmt.Errorf("unable to execute byte array -> private key conversion, %w", err) + } + + return secretKey, keyBuff, nil +} + func ReadConsensusKey(manager secrets.SecretsManager) (*ecdsa.PrivateKey, error) { validatorKey, err := manager.GetSecret(secrets.ValidatorKey) if err != nil { return nil, err } - return BytesToPrivateKey(validatorKey) + return BytesToECDSAPrivateKey(validatorKey) } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 25ac9a95c5..be8738314d 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -15,13 +15,13 @@ import ( func TestKeyEncoding(t *testing.T) { for i := 0; i < 10; i++ { - priv, _ := GenerateKey() + priv, _ := GenerateECDSAKey() // marshall private key - buf, err := MarshalPrivateKey(priv) + buf, err := MarshalECDSAPrivateKey(priv) assert.NoError(t, err) - priv0, err := ParsePrivateKey(buf) + priv0, err := ParseECDSAPrivateKey(buf) assert.NoError(t, err) assert.Equal(t, priv, priv0) @@ -204,7 +204,7 @@ func TestPrivateKeyRead(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { t.Parallel() - privateKey, err := BytesToPrivateKey([]byte(testCase.privateKeyHex)) + privateKey, err := BytesToECDSAPrivateKey([]byte(testCase.privateKeyHex)) if err != nil && !testCase.shouldFail { t.Fatalf("Unable to parse private key, %v", err) } diff --git a/crypto/txsigner_test.go b/crypto/txsigner_test.go index 1141893dbe..5cfe2568c1 100644 --- a/crypto/txsigner_test.go +++ b/crypto/txsigner_test.go @@ -12,7 +12,7 @@ func TestFrontierSigner(t *testing.T) { signer := &FrontierSigner{} toAddress := types.StringToAddress("1") - key, err := GenerateKey() + key, err := GenerateECDSAKey() assert.NoError(t, err) txn := &types.Transaction{ @@ -76,7 +76,7 @@ func TestEIP155Signer_Sender(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { t.Parallel() - key, keyGenError := GenerateKey() + key, keyGenError := GenerateECDSAKey() if keyGenError != nil { t.Fatalf("Unable to generate key") } @@ -109,7 +109,7 @@ func TestEIP155Signer_ChainIDMismatch(t *testing.T) { toAddress := types.StringToAddress("1") for _, chainIDTop := range chainIDS { - key, keyGenError := GenerateKey() + key, keyGenError := GenerateECDSAKey() if keyGenError != nil { t.Fatalf("Unable to generate key") } diff --git a/e2e/framework/config.go b/e2e/framework/config.go index ca6b0ec81d..40aba049fc 100644 --- a/e2e/framework/config.go +++ b/e2e/framework/config.go @@ -8,6 +8,7 @@ import ( "github.com/0xPolygon/polygon-edge/consensus/ibft" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" ) type ConsensusType int @@ -26,30 +27,31 @@ type SrvAccount struct { // TestServerConfig for the test server type TestServerConfig struct { ReservedPorts []ReservedPort - JSONRPCPort int // The JSON RPC endpoint port - GRPCPort int // The GRPC endpoint port - LibP2PPort int // The Libp2p endpoint port - Seal bool // Flag indicating if blocks should be sealed - RootDir string // The root directory for test environment - IBFTDirPrefix string // The prefix of data directory for IBFT - IBFTDir string // The name of data directory for IBFT - PremineAccts []*SrvAccount // Accounts with existing balances (genesis accounts) - GenesisValidatorBalance *big.Int // Genesis the balance for the validators - DevStakers []types.Address // List of initial staking addresses for the staking SC with dev consensus - Consensus ConsensusType // Consensus MechanismType - Bootnodes []string // Bootnode Addresses - PriceLimit *uint64 // Minimum gas price limit to enforce for acceptance into the pool - DevInterval int // Dev consensus update interval [s] - EpochSize uint64 // The epoch size in blocks for the IBFT layer - BlockGasLimit uint64 // Block gas limit - BlockGasTarget uint64 // Gas target for new blocks - ShowsLog bool // Flag specifying if logs are shown - IsPos bool // Specifies the mechanism used for IBFT (PoA / PoS) - Signer *crypto.EIP155Signer // Signer used for transactions - MinValidatorCount uint64 // Min validator count - MaxValidatorCount uint64 // Max validator count - BlockTime uint64 // Minimum block generation time (in s) - IBFTBaseTimeout uint64 // Base Timeout in seconds for IBFT + JSONRPCPort int // The JSON RPC endpoint port + GRPCPort int // The GRPC endpoint port + LibP2PPort int // The Libp2p endpoint port + Seal bool // Flag indicating if blocks should be sealed + RootDir string // The root directory for test environment + IBFTDirPrefix string // The prefix of data directory for IBFT + IBFTDir string // The name of data directory for IBFT + PremineAccts []*SrvAccount // Accounts with existing balances (genesis accounts) + GenesisValidatorBalance *big.Int // Genesis the balance for the validators + DevStakers []types.Address // List of initial staking addresses for the staking SC with dev + Consensus ConsensusType // Consensus MechanismType + ValidatorType validators.ValidatorType // Validator Type + Bootnodes []string // Bootnode Addresses + PriceLimit *uint64 // Minimum gas price limit to enforce for acceptance into the pool + DevInterval int // Dev consensus update interval [s] + EpochSize uint64 // The epoch size in blocks for the IBFT layer + BlockGasLimit uint64 // Block gas limit + BlockGasTarget uint64 // Gas target for new blocks + ShowsLog bool // Flag specifying if logs are shown + IsPos bool // Specifies the mechanism used for IBFT (PoA / PoS) + Signer *crypto.EIP155Signer // Signer used for transactions + MinValidatorCount uint64 // Min validator count + MaxValidatorCount uint64 // Max validator count + BlockTime uint64 // Minimum block generation time (in s) + IBFTBaseTimeout uint64 // Base Timeout in seconds for IBFT } // DataDir returns path of data directory server uses @@ -108,6 +110,11 @@ func (t *TestServerConfig) SetConsensus(c ConsensusType) { t.Consensus = c } +// SetValidatorType callback sets validator type +func (t *TestServerConfig) SetValidatorType(vt validators.ValidatorType) { + t.ValidatorType = vt +} + // SetDevInterval sets the update interval for the dev consensus func (t *TestServerConfig) SetDevInterval(interval int) { t.DevInterval = interval diff --git a/e2e/framework/testserver.go b/e2e/framework/testserver.go index da2a46785a..77718bd2ae 100644 --- a/e2e/framework/testserver.go +++ b/e2e/framework/testserver.go @@ -18,14 +18,12 @@ import ( "testing" "time" - "github.com/umbracle/ethgo" - "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/genesis" ibftSwitch "github.com/0xPolygon/polygon-edge/command/ibft/switch" initCmd "github.com/0xPolygon/polygon-edge/command/secrets/init" "github.com/0xPolygon/polygon-edge/command/server" - "github.com/0xPolygon/polygon-edge/consensus/ibft" + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" "github.com/0xPolygon/polygon-edge/crypto" stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" @@ -36,8 +34,10 @@ import ( "github.com/0xPolygon/polygon-edge/server/proto" txpoolProto "github.com/0xPolygon/polygon-edge/txpool/proto" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" "github.com/hashicorp/go-hclog" "github.com/libp2p/go-libp2p-core/peer" + "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/jsonrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -76,6 +76,7 @@ func NewTestServer(t *testing.T, rootDir string, callback TestServerConfigCallba JSONRPCPort: ports[2].Port(), RootDir: rootDir, Signer: crypto.NewEIP155Signer(100), + ValidatorType: validators.ECDSAValidatorType, } if callback != nil { @@ -210,7 +211,7 @@ func (t *TestServer) SecretsInit() (*InitIBFTResult, error) { } // Generate the IBFT validator private key - validatorKey, validatorKeyEncoded, keyErr := crypto.GenerateAndEncodePrivateKey() + validatorKey, validatorKeyEncoded, keyErr := crypto.GenerateAndEncodeECDSAPrivateKey() if keyErr != nil { return nil, keyErr } @@ -231,6 +232,19 @@ func (t *TestServer) SecretsInit() (*InitIBFTResult, error) { return nil, setErr } + if t.Config.ValidatorType == validators.BLSValidatorType { + // Generate the BLS Key + _, bksKeyEncoded, keyErr := crypto.GenerateAndEncodeBLSSecretKey() + if keyErr != nil { + return nil, keyErr + } + + // Write the networking private key to the secrets manager storage + if setErr := localSecretsManager.SetSecret(secrets.ValidatorBLSKey, bksKeyEncoded); setErr != nil { + return nil, setErr + } + } + // Get the node ID from the private key nodeID, err := peer.IDFromPrivateKey(libp2pKey) if err != nil { @@ -257,7 +271,11 @@ func (t *TestServer) GenerateGenesis() error { // add consensus flags switch t.Config.Consensus { case ConsensusIBFT: - args = append(args, "--consensus", "ibft") + args = append( + args, + "--consensus", "ibft", + "--ibft-validator-type", string(t.Config.ValidatorType), + ) if t.Config.IBFTDirPrefix == "" { return errors.New("prefix of IBFT directory is not set") @@ -268,8 +286,13 @@ func (t *TestServer) GenerateGenesis() error { if t.Config.EpochSize != 0 { args = append(args, "--epoch-size", strconv.FormatUint(t.Config.EpochSize, 10)) } + case ConsensusDev: - args = append(args, "--consensus", "dev") + args = append( + args, + "--consensus", "dev", + "--ibft-validator-type", string(t.Config.ValidatorType), + ) // Set up any initial staker addresses for the predeployed Staking SC for _, stakerAddress := range t.Config.DevStakers { @@ -310,6 +333,12 @@ func (t *TestServer) GenerateGenesis() error { cmd := exec.Command(binaryName, args...) cmd.Dir = t.Config.RootDir + if t.Config.ShowsLog { + stdout := io.Writer(os.Stdout) + cmd.Stdout = stdout + cmd.Stderr = stdout + } + return cmd.Run() } @@ -396,7 +425,7 @@ func (t *TestServer) Start(ctx context.Context) error { return err } -func (t *TestServer) SwitchIBFTType(typ ibft.MechanismType, from uint64, to, deployment *uint64) error { +func (t *TestServer) SwitchIBFTType(typ fork.IBFTType, from uint64, to, deployment *uint64) error { t.t.Helper() ibftSwitchCmd := ibftSwitch.GetCommand() @@ -412,6 +441,9 @@ func (t *TestServer) SwitchIBFTType(typ ibft.MechanismType, from uint64, to, dep "--from", strconv.FormatUint(from, 10), ) + // Default ibft validator type for e2e tests is ECDSA + args = append(args, "--ibft-validator-type", string(validators.ECDSAValidatorType)) + if to != nil { args = append(args, "--to", strconv.FormatUint(*to, 10)) } diff --git a/e2e/ibft_test.go b/e2e/ibft_test.go index 59a19993ec..b606b04d8d 100644 --- a/e2e/ibft_test.go +++ b/e2e/ibft_test.go @@ -6,14 +6,14 @@ import ( "testing" "time" - "github.com/umbracle/ethgo" - "github.com/0xPolygon/polygon-edge/command/server/config" - "github.com/0xPolygon/polygon-edge/consensus/ibft" + ibftSigner "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" "github.com/0xPolygon/polygon-edge/e2e/framework" "github.com/0xPolygon/polygon-edge/helper/tests" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" "github.com/stretchr/testify/assert" + "github.com/umbracle/ethgo" ) // TestIbft_Transfer sends a transfer transaction (EOA -> EOA) @@ -23,16 +23,25 @@ func TestIbft_Transfer(t *testing.T) { name string blockTime uint64 ibftBaseTimeout uint64 + validatorType validators.ValidatorType }{ { name: "default block time", blockTime: config.DefaultBlockTime, ibftBaseTimeout: 0, // use default value + validatorType: validators.ECDSAValidatorType, }, { name: "longer block time", blockTime: 10, ibftBaseTimeout: 20, + validatorType: validators.ECDSAValidatorType, + }, + { + name: "with BLS", + blockTime: config.DefaultBlockTime, + ibftBaseTimeout: 0, // use default value + validatorType: validators.BLSValidatorType, }, } @@ -51,12 +60,13 @@ func TestIbft_Transfer(t *testing.T) { config.SetSeal(true) config.SetBlockTime(tc.blockTime) config.SetIBFTBaseTimeout(tc.ibftBaseTimeout) + config.SetValidatorType(tc.validatorType) }, ) var ( startTimeout = time.Duration(tc.ibftBaseTimeout+60) * time.Second - txTimeout = time.Duration(tc.ibftBaseTimeout+10) * time.Second + txTimeout = time.Duration(tc.ibftBaseTimeout+20) * time.Second ) ctxForStart, cancelStart := context.WithTimeout(context.Background(), startTimeout) @@ -141,7 +151,7 @@ func TestIbft_TransactionFeeRecipient(t *testing.T) { // Deploy contract deployTx := &framework.PreparedTransaction{ From: senderAddr, - GasPrice: big.NewInt(10), + GasPrice: big.NewInt(0), // don't want gas fee to paid to a proposer Gas: 1000000, Value: big.NewInt(0), Input: framework.MethodSig("setA1"), @@ -170,8 +180,13 @@ func TestIbft_TransactionFeeRecipient(t *testing.T) { assert.NotNil(t, receipt.BlockHash) block, err := clt.Eth().GetBlockByHash(receipt.BlockHash, false) assert.NoError(t, err) - extraData := &ibft.IstanbulExtra{} - extraDataWithoutVanity := block.ExtraData[ibft.IstanbulExtraVanity:] + extraData := &ibftSigner.IstanbulExtra{ + Validators: validators.NewECDSAValidatorSet(), + CommittedSeals: &ibftSigner.SerializedSeal{}, + ParentCommittedSeals: &ibftSigner.SerializedSeal{}, + } + extraDataWithoutVanity := block.ExtraData[ibftSigner.IstanbulExtraVanity:] + err = extraData.UnmarshalRLP(extraDataWithoutVanity) assert.NoError(t, err) diff --git a/e2e/logs_test.go b/e2e/logs_test.go index 99162331c4..bc2f2006c5 100644 --- a/e2e/logs_test.go +++ b/e2e/logs_test.go @@ -12,124 +12,151 @@ import ( "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/helper/tests" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" "github.com/stretchr/testify/assert" "golang.org/x/crypto/sha3" ) func TestNewFilter_Logs(t *testing.T) { - key, addr := tests.GenerateKeyAndAddr(t) - - ibftManager := framework.NewIBFTServersManager( - t, - 1, - IBFTDirPrefix, - func(i int, config *framework.TestServerConfig) { - config.Premine(addr, framework.EthToWei(10)) - config.SetBlockTime(1) - }, - ) - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - ibftManager.StartServers(ctx) - srv := ibftManager.GetServer(0) - - ctx1, cancel1 := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer cancel1() - - contractAddr, err := srv.DeployContract(ctx1, sampleByteCode, key) - castedContractAddr := types.Address(contractAddr) - - if err != nil { - t.Fatal(err) + runTest := func(t *testing.T, validatorType validators.ValidatorType) { + t.Helper() + + key, addr := tests.GenerateKeyAndAddr(t) + + ibftManager := framework.NewIBFTServersManager( + t, + 1, + IBFTDirPrefix, + func(i int, config *framework.TestServerConfig) { + config.SetValidatorType(validatorType) + config.Premine(addr, framework.EthToWei(10)) + config.SetBlockTime(1) + }, + ) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + ibftManager.StartServers(ctx) + srv := ibftManager.GetServer(0) + + ctx1, cancel1 := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer cancel1() + + contractAddr, err := srv.DeployContract(ctx1, sampleByteCode, key) + castedContractAddr := types.Address(contractAddr) + + if err != nil { + t.Fatal(err) + } + + txpoolClient := srv.TxnPoolOperator() + jsonRPCClient := srv.JSONRPC() + + id, err := jsonRPCClient.Eth().NewFilter(ðgo.LogFilter{}) + assert.NoError(t, err) + + txn, err := tests.GenerateAddTxnReq(tests.GenerateTxReqParams{ + Nonce: 1, // The first transaction was a contract deployment + ReferenceAddr: addr, + ReferenceKey: key, + ToAddress: castedContractAddr, + GasPrice: big.NewInt(framework.DefaultGasPrice), + Input: framework.MethodSig("setA1"), + }) + if err != nil { + return + } + + addTxnContext, addTxnCancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer addTxnCancelFn() + + addResp, addErr := txpoolClient.AddTxn(addTxnContext, txn) + if addErr != nil { + t.Fatalf("Unable to add transaction, %v", addErr) + } + + receiptContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer cancelFn() + + txHash := ethgo.Hash(types.StringToHash(addResp.TxHash)) + if _, receiptErr := srv.WaitForReceipt(receiptContext, txHash); receiptErr != nil { + t.Fatalf("Unable to wait for receipt, %v", receiptErr) + } + + res, err := jsonRPCClient.Eth().GetFilterChanges(id) + + assert.NoError(t, err) + assert.Equal(t, 1, len(res)) } - txpoolClient := srv.TxnPoolOperator() - jsonRPCClient := srv.JSONRPC() - - id, err := jsonRPCClient.Eth().NewFilter(ðgo.LogFilter{}) - assert.NoError(t, err) - - txn, err := tests.GenerateAddTxnReq(tests.GenerateTxReqParams{ - Nonce: 1, // The first transaction was a contract deployment - ReferenceAddr: addr, - ReferenceKey: key, - ToAddress: castedContractAddr, - GasPrice: big.NewInt(framework.DefaultGasPrice), - Input: framework.MethodSig("setA1"), + t.Run("ECDSA", func(t *testing.T) { + runTest(t, validators.ECDSAValidatorType) }) - if err != nil { - return - } - - addTxnContext, addTxnCancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer addTxnCancelFn() - - addResp, addErr := txpoolClient.AddTxn(addTxnContext, txn) - if addErr != nil { - t.Fatalf("Unable to add transaction, %v", addErr) - } - - receiptContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer cancelFn() - - txHash := ethgo.Hash(types.StringToHash(addResp.TxHash)) - if _, receiptErr := srv.WaitForReceipt(receiptContext, txHash); receiptErr != nil { - t.Fatalf("Unable to wait for receipt, %v", receiptErr) - } - res, err := jsonRPCClient.Eth().GetFilterChanges(id) - - assert.NoError(t, err) - assert.Equal(t, 1, len(res)) + t.Run("BLS", func(t *testing.T) { + runTest(t, validators.BLSValidatorType) + }) } func TestNewFilter_Block(t *testing.T) { - fromKey, from := tests.GenerateKeyAndAddr(t) - _, to := tests.GenerateKeyAndAddr(t) - - ibftManager := framework.NewIBFTServersManager( - t, - 1, - IBFTDirPrefix, - func(i int, config *framework.TestServerConfig) { - config.Premine(from, framework.EthToWei(10)) - config.SetBlockTime(1) - }, - ) - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - - ibftManager.StartServers(ctx) - srv := ibftManager.GetServer(0) - - client := srv.JSONRPC() - - id, err := client.Eth().NewBlockFilter() - assert.NoError(t, err) - - ctx, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer cancelFn() - - if _, sendErr := srv.SendRawTx(ctx, &framework.PreparedTransaction{ - From: from, - To: &to, - GasPrice: big.NewInt(10000), - Gas: 1000000, - Value: big.NewInt(10000), - }, fromKey); err != nil { - t.Fatalf("Unable to send transaction %v", sendErr) + runTest := func(t *testing.T, validatorType validators.ValidatorType) { + t.Helper() + + fromKey, from := tests.GenerateKeyAndAddr(t) + _, to := tests.GenerateKeyAndAddr(t) + + ibftManager := framework.NewIBFTServersManager( + t, + 1, + IBFTDirPrefix, + func(i int, config *framework.TestServerConfig) { + config.SetValidatorType(validatorType) + config.Premine(from, framework.EthToWei(10)) + config.SetBlockTime(1) + }, + ) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + ibftManager.StartServers(ctx) + srv := ibftManager.GetServer(0) + + client := srv.JSONRPC() + + id, err := client.Eth().NewBlockFilter() + assert.NoError(t, err) + + ctx, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer cancelFn() + + if _, sendErr := srv.SendRawTx(ctx, &framework.PreparedTransaction{ + From: from, + To: &to, + GasPrice: big.NewInt(10000), + Gas: 1000000, + Value: big.NewInt(10000), + }, fromKey); err != nil { + t.Fatalf("Unable to send transaction %v", sendErr) + } + + assert.NoError(t, err) + + // verify filter picked up block changes + blocks, err := client.Eth().GetFilterChangesBlock(id) + assert.NoError(t, err) + assert.Greater(t, len(blocks), 0) } - assert.NoError(t, err) + t.Run("ECDSA", func(t *testing.T) { + runTest(t, validators.ECDSAValidatorType) + }) - // verify filter picked up block changes - blocks, err := client.Eth().GetFilterChangesBlock(id) - assert.NoError(t, err) - assert.Greater(t, len(blocks), 0) + t.Run("BLS", func(t *testing.T) { + runTest(t, validators.BLSValidatorType) + }) } func TestFilterValue(t *testing.T) { @@ -145,102 +172,115 @@ func TestFilterValue(t *testing.T) { // // 3. Query the block's bloom filter to make sure the data has been properly inserted. // - key, addr := tests.GenerateKeyAndAddr(t) + runTest := func(t *testing.T, validatorType validators.ValidatorType) { + t.Helper() - ibftManager := framework.NewIBFTServersManager( - t, - 1, - IBFTDirPrefix, - func(i int, config *framework.TestServerConfig) { - config.Premine(addr, framework.EthToWei(10)) - config.SetBlockTime(1) - }, - ) + key, addr := tests.GenerateKeyAndAddr(t) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() + ibftManager := framework.NewIBFTServersManager( + t, + 1, + IBFTDirPrefix, + func(i int, config *framework.TestServerConfig) { + config.SetValidatorType(validatorType) + config.Premine(addr, framework.EthToWei(10)) + config.SetBlockTime(1) + }, + ) - ibftManager.StartServers(ctx) - srv := ibftManager.GetServer(0) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() - deployCtx, deployCancel := context.WithTimeout(context.Background(), time.Minute) - defer deployCancel() + ibftManager.StartServers(ctx) + srv := ibftManager.GetServer(0) - contractAddr, err := srv.DeployContract(deployCtx, bloomFilterTestBytecode, key) + deployCtx, deployCancel := context.WithTimeout(context.Background(), time.Minute) + defer deployCancel() - if err != nil { - t.Fatal(err) - } + contractAddr, err := srv.DeployContract(deployCtx, bloomFilterTestBytecode, key) - txpoolClient := srv.TxnPoolOperator() - jsonRPCClient := srv.JSONRPC() + if err != nil { + t.Fatal(err) + } - // Encode event signature - hash := sha3.NewLegacyKeccak256() - decodeString := []byte("MyEvent(address,uint256)") - hash.Write(decodeString) + txpoolClient := srv.TxnPoolOperator() + jsonRPCClient := srv.JSONRPC() - buf := hash.Sum(nil) + // Encode event signature + hash := sha3.NewLegacyKeccak256() + decodeString := []byte("MyEvent(address,uint256)") + hash.Write(decodeString) - // Convert to right format - var ( - placeholderWrapper []*ethgo.Hash - placeholder ethgo.Hash - filterEventHashes [][]*ethgo.Hash - filterAddresses []ethgo.Address - ) + buf := hash.Sum(nil) - copy(placeholder[:], buf) - placeholderWrapper = append(placeholderWrapper, &placeholder) + // Convert to right format + var ( + placeholderWrapper []*ethgo.Hash + placeholder ethgo.Hash + filterEventHashes [][]*ethgo.Hash + filterAddresses []ethgo.Address + ) - filterEventHashes = append(filterEventHashes, placeholderWrapper) - filterAddresses = append(filterAddresses, contractAddr) + copy(placeholder[:], buf) + placeholderWrapper = append(placeholderWrapper, &placeholder) - filterID, err := jsonRPCClient.Eth().NewFilter(ðgo.LogFilter{ - Address: filterAddresses, - Topics: filterEventHashes, - }) + filterEventHashes = append(filterEventHashes, placeholderWrapper) + filterAddresses = append(filterAddresses, contractAddr) - assert.NoError(t, err) + filterID, err := jsonRPCClient.Eth().NewFilter(ðgo.LogFilter{ + Address: filterAddresses, + Topics: filterEventHashes, + }) - castedContractAddr := types.Address(contractAddr) + assert.NoError(t, err) - if err != nil { - t.Fatal(err) - } + castedContractAddr := types.Address(contractAddr) - txn, err := tests.GenerateAddTxnReq(tests.GenerateTxReqParams{ - Nonce: 1, - ReferenceAddr: addr, - ReferenceKey: key, - ToAddress: castedContractAddr, - GasPrice: big.NewInt(framework.DefaultGasPrice), - Input: framework.MethodSig("TriggerMyEvent"), - }) + if err != nil { + t.Fatal(err) + } - if err != nil { - return - } + txn, err := tests.GenerateAddTxnReq(tests.GenerateTxReqParams{ + Nonce: 1, + ReferenceAddr: addr, + ReferenceKey: key, + ToAddress: castedContractAddr, + GasPrice: big.NewInt(framework.DefaultGasPrice), + Input: framework.MethodSig("TriggerMyEvent"), + }) - addTxnContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer cancelFn() + if err != nil { + return + } - addResp, addErr := txpoolClient.AddTxn(addTxnContext, txn) - if addErr != nil { - return - } + addTxnContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer cancelFn() + + addResp, addErr := txpoolClient.AddTxn(addTxnContext, txn) + if addErr != nil { + return + } + + receiptContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer cancelFn() - receiptContext, cancelFn := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer cancelFn() + txHash := ethgo.Hash(types.StringToHash(addResp.TxHash)) + if _, receiptErr := srv.WaitForReceipt(receiptContext, txHash); receiptErr != nil { + return + } - txHash := ethgo.Hash(types.StringToHash(addResp.TxHash)) - if _, receiptErr := srv.WaitForReceipt(receiptContext, txHash); receiptErr != nil { - return + res, err := jsonRPCClient.Eth().GetFilterChanges(filterID) + + assert.NoError(t, err) + assert.Len(t, res, 1) + assert.Equal(t, "0x000000000000000000000000000000000000000000000000000000000000002a", hex.EncodeToHex(res[0].Data)) } - res, err := jsonRPCClient.Eth().GetFilterChanges(filterID) + t.Run("ECDSA", func(t *testing.T) { + runTest(t, validators.ECDSAValidatorType) + }) - assert.NoError(t, err) - assert.Len(t, res, 1) - assert.Equal(t, "0x000000000000000000000000000000000000000000000000000000000000002a", hex.EncodeToHex(res[0].Data)) + t.Run("BLS", func(t *testing.T) { + runTest(t, validators.BLSValidatorType) + }) } diff --git a/e2e/pos_poa_switch_test.go b/e2e/pos_poa_switch_test.go index 63aecf8cee..fc209ad6f9 100644 --- a/e2e/pos_poa_switch_test.go +++ b/e2e/pos_poa_switch_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/0xPolygon/polygon-edge/consensus/ibft" + "github.com/0xPolygon/polygon-edge/consensus/ibft/fork" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/e2e/framework" @@ -41,7 +41,7 @@ func TestPoAPoSSwitch(t *testing.T) { }) // Set switch configuration into genesis.json - err := ibftManager.GetServer(0).SwitchIBFTType(ibft.PoS, posStartAt, nil, &posDeployContractAt) + err := ibftManager.GetServer(0).SwitchIBFTType(fork.PoS, posStartAt, nil, &posDeployContractAt) assert.NoError(t, err) // Get server slice @@ -82,7 +82,7 @@ func TestPoAPoSSwitch(t *testing.T) { snapshotValidators := make([]types.Address, len(res.Validators)) for idx, v := range res.Validators { - snapshotValidators[idx] = types.StringToAddress(v.Address) + snapshotValidators[idx] = types.BytesToAddress(v.Data) } assert.ElementsMatch(t, expectedValidators, snapshotValidators) diff --git a/e2e/pos_test.go b/e2e/pos_test.go index b0fac56ea0..3528c88bc7 100644 --- a/e2e/pos_test.go +++ b/e2e/pos_test.go @@ -10,8 +10,6 @@ import ( "time" ibftOp "github.com/0xPolygon/polygon-edge/consensus/ibft/proto" - "github.com/umbracle/ethgo" - "github.com/0xPolygon/polygon-edge/contracts/staking" "github.com/0xPolygon/polygon-edge/crypto" "github.com/0xPolygon/polygon-edge/e2e/framework" @@ -21,6 +19,7 @@ import ( "github.com/0xPolygon/polygon-edge/types" "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + "github.com/umbracle/ethgo" "github.com/umbracle/ethgo/jsonrpc" ) @@ -124,6 +123,10 @@ func TestPoS_ValidatorBoundaries(t *testing.T) { config.SetMaxValidatorCount(maxValidatorCount) }) + t.Cleanup(func() { + ibftManager.StopServers() + }) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() ibftManager.StartServers(ctx) @@ -182,6 +185,10 @@ func TestPoS_Stake(t *testing.T) { config.SetIBFTPoS(true) }) + t.Cleanup(func() { + ibftManager.StopServers() + }) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() ibftManager.StartServers(ctx) @@ -234,7 +241,7 @@ func TestPoS_Unstake(t *testing.T) { t, numGenesisValidators, IBFTDirPrefix, - func(i int, config *framework.TestServerConfig) { + func(_ int, config *framework.TestServerConfig) { // Premine to send unstake transaction config.SetSeal(true) config.SetEpochSize(2) // Need to leave room for the endblock @@ -242,6 +249,10 @@ func TestPoS_Unstake(t *testing.T) { config.SetIBFTPoS(true) }) + t.Cleanup(func() { + ibftManager.StopServers() + }) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() ibftManager.StartServers(ctx) @@ -819,7 +830,7 @@ func TestSnapshotUpdating(t *testing.T) { } // Wait for all the nodes to reach the epoch block - waitErrors := framework.WaitForServersToSeal(servers, nextEpoch) + waitErrors := framework.WaitForServersToSeal(servers, nextEpoch+1) if len(waitErrors) != 0 { t.Fatalf("Unable to wait for all nodes to seal blocks, %v", waitErrors) @@ -848,7 +859,7 @@ func TestSnapshotUpdating(t *testing.T) { ctxCancelFn() for _, validator := range snapshot.Validators { - if validator.Address == referenceAddr.String() { + if types.BytesToAddress(validator.Data) == referenceAddr { return true } } diff --git a/e2e/syncer_test.go b/e2e/syncer_test.go index b59b92c762..972d3c0af7 100644 --- a/e2e/syncer_test.go +++ b/e2e/syncer_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/0xPolygon/polygon-edge/e2e/framework" + "github.com/0xPolygon/polygon-edge/validators" ) func TestClusterBlockSync(t *testing.T) { @@ -15,32 +16,46 @@ func TestClusterBlockSync(t *testing.T) { desiredHeight = 10 ) - // Start IBFT cluster (4 Validator + 2 Non-Validator) - ibftManager := framework.NewIBFTServersManager( - t, - IBFTMinNodes+numNonValidators, - IBFTDirPrefix, func(i int, config *framework.TestServerConfig) { - if i >= IBFTMinNodes { - // Other nodes should not be in the validator set - dirPrefix := "polygon-edge-non-validator-" - config.SetIBFTDirPrefix(dirPrefix) - config.SetIBFTDir(fmt.Sprintf("%s%d", dirPrefix, i)) - } - config.SetSeal(i < IBFTMinNodes) - }) - - startContext, startCancelFn := context.WithTimeout(context.Background(), time.Minute) - defer startCancelFn() - ibftManager.StartServers(startContext) - - servers := make([]*framework.TestServer, 0) - for i := 0; i < IBFTMinNodes+numNonValidators; i++ { - servers = append(servers, ibftManager.GetServer(i)) - } - // All nodes should have mined the same block eventually - waitErrors := framework.WaitForServersToSeal(servers, desiredHeight) + runTest := func(t *testing.T, validatorType validators.ValidatorType) { + t.Helper() + + // Start IBFT cluster (4 Validator + 2 Non-Validator) + ibftManager := framework.NewIBFTServersManager( + t, + IBFTMinNodes+numNonValidators, + IBFTDirPrefix, func(i int, config *framework.TestServerConfig) { + config.SetValidatorType(validatorType) + + if i >= IBFTMinNodes { + // Other nodes should not be in the validator set + dirPrefix := "polygon-edge-non-validator-" + config.SetIBFTDirPrefix(dirPrefix) + config.SetIBFTDir(fmt.Sprintf("%s%d", dirPrefix, i)) + } + config.SetSeal(i < IBFTMinNodes) + }) + + startContext, startCancelFn := context.WithTimeout(context.Background(), time.Minute) + defer startCancelFn() + ibftManager.StartServers(startContext) - if len(waitErrors) != 0 { - t.Fatalf("Unable to wait for all nodes to seal blocks, %v", waitErrors) + servers := make([]*framework.TestServer, 0) + for i := 0; i < IBFTMinNodes+numNonValidators; i++ { + servers = append(servers, ibftManager.GetServer(i)) + } + // All nodes should have mined the same block eventually + waitErrors := framework.WaitForServersToSeal(servers, desiredHeight) + + if len(waitErrors) != 0 { + t.Fatalf("Unable to wait for all nodes to seal blocks, %v", waitErrors) + } } + + t.Run("ECDSA", func(t *testing.T) { + runTest(t, validators.ECDSAValidatorType) + }) + + t.Run("BLS", func(t *testing.T) { + runTest(t, validators.BLSValidatorType) + }) } diff --git a/e2e/transaction_test.go b/e2e/transaction_test.go index c0d4b1b073..ff7bf54f88 100644 --- a/e2e/transaction_test.go +++ b/e2e/transaction_test.go @@ -19,6 +19,7 @@ import ( "github.com/0xPolygon/polygon-edge/e2e/framework" "github.com/0xPolygon/polygon-edge/helper/tests" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" "github.com/stretchr/testify/assert" "github.com/umbracle/ethgo/jsonrpc" ) @@ -350,121 +351,133 @@ func addStressTxnsWithHashes( // that modify it's state, and make sure that all // transactions were correctly executed func Test_TransactionIBFTLoop(t *testing.T) { - senderKey, sender := tests.GenerateKeyAndAddr(t) - defaultBalance := framework.EthToWei(100) - - // Set up the test server - ibftManager := framework.NewIBFTServersManager( - t, - IBFTMinNodes, - IBFTDirPrefix, - func(i int, config *framework.TestServerConfig) { - config.Premine(sender, defaultBalance) - config.SetSeal(true) - config.SetBlockLimit(20000000) - }) - - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - ibftManager.StartServers(ctx) - - srv := ibftManager.GetServer(0) - client := srv.JSONRPC() + runTest := func(t *testing.T, validatorType validators.ValidatorType) { + t.Helper() - // Deploy the stress test contract - deployCtx, deployCancel := context.WithTimeout(context.Background(), framework.DefaultTimeout) - defer deployCancel() + senderKey, sender := tests.GenerateKeyAndAddr(t) + defaultBalance := framework.EthToWei(100) - buf, err := hex.DecodeString(stressTestBytecode) - if err != nil { - t.Fatalf("Unable to decode bytecode, %v", err) - } + // Set up the test server + ibftManager := framework.NewIBFTServersManager( + t, + IBFTMinNodes, + IBFTDirPrefix, + func(i int, config *framework.TestServerConfig) { + config.SetValidatorType(validatorType) + config.Premine(sender, defaultBalance) + config.SetSeal(true) + config.SetBlockLimit(20000000) + }) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + ibftManager.StartServers(ctx) + + srv := ibftManager.GetServer(0) + client := srv.JSONRPC() + + // Deploy the stress test contract + deployCtx, deployCancel := context.WithTimeout(context.Background(), framework.DefaultTimeout) + defer deployCancel() + + buf, err := hex.DecodeString(stressTestBytecode) + if err != nil { + t.Fatalf("Unable to decode bytecode, %v", err) + } - deployTx := &framework.PreparedTransaction{ - From: sender, - GasPrice: big.NewInt(framework.DefaultGasPrice), - Gas: framework.DefaultGasLimit, - Value: big.NewInt(0), - Input: buf, - } - receipt, err := srv.SendRawTx(deployCtx, deployTx, senderKey) + deployTx := &framework.PreparedTransaction{ + From: sender, + GasPrice: big.NewInt(framework.DefaultGasPrice), + Gas: framework.DefaultGasLimit, + Value: big.NewInt(0), + Input: buf, + } + receipt, err := srv.SendRawTx(deployCtx, deployTx, senderKey) - if err != nil { - t.Fatalf("Unable to send transaction, %v", err) - } + if err != nil { + t.Fatalf("Unable to send transaction, %v", err) + } - assert.NotNil(t, receipt) + assert.NotNil(t, receipt) - contractAddr := receipt.ContractAddress + contractAddr := receipt.ContractAddress - if err != nil { - t.Fatalf("Unable to send transaction, %v", err) - } + if err != nil { + t.Fatalf("Unable to send transaction, %v", err) + } - count, countErr := getCount(sender, contractAddr, client) - if countErr != nil { - t.Fatalf("Unable to call count method, %v", countErr) - } + count, countErr := getCount(sender, contractAddr, client) + if countErr != nil { + t.Fatalf("Unable to call count method, %v", countErr) + } - // Check that the count is 0 before running the test - assert.Equalf(t, "0", count.String(), "Count doesn't match") + // Check that the count is 0 before running the test + assert.Equalf(t, "0", count.String(), "Count doesn't match") - // Send ~50 transactions - numTransactions := 50 + // Send ~50 transactions + numTransactions := 50 - var wg sync.WaitGroup + var wg sync.WaitGroup - wg.Add(numTransactions) + wg.Add(numTransactions) - // Add stress test transactions - txHashes := addStressTxnsWithHashes( - t, - srv, - numTransactions, - types.StringToAddress(contractAddr.String()), - senderKey, - ) - if len(txHashes) != numTransactions { - t.Fatalf( - "Invalid number of txns sent [sent %d, expected %d]", - len(txHashes), + // Add stress test transactions + txHashes := addStressTxnsWithHashes( + t, + srv, numTransactions, + types.StringToAddress(contractAddr.String()), + senderKey, ) - } + if len(txHashes) != numTransactions { + t.Fatalf( + "Invalid number of txns sent [sent %d, expected %d]", + len(txHashes), + numTransactions, + ) + } - // For each transaction hash, wait for it to get included into a block - for index, txHash := range txHashes { - waitCtx, waitCancel := context.WithTimeout(context.Background(), time.Minute*3) + // For each transaction hash, wait for it to get included into a block + for index, txHash := range txHashes { + waitCtx, waitCancel := context.WithTimeout(context.Background(), time.Minute*3) - receipt, receiptErr := tests.WaitForReceipt(waitCtx, client.Eth(), txHash) - if receipt == nil { - t.Fatalf("Unable to get receipt for hash index [%d]", index) - } else if receiptErr != nil { - t.Fatalf("Unable to get receipt for hash index [%d], %v", index, receiptErr) - } + receipt, receiptErr := tests.WaitForReceipt(waitCtx, client.Eth(), txHash) + if receipt == nil { + t.Fatalf("Unable to get receipt for hash index [%d]", index) + } else if receiptErr != nil { + t.Fatalf("Unable to get receipt for hash index [%d], %v", index, receiptErr) + } - waitCancel() - wg.Done() - } + waitCancel() + wg.Done() + } - wg.Wait() + wg.Wait() - statusCtx, statusCancel := context.WithTimeout(context.Background(), time.Second*30) - defer statusCancel() + statusCtx, statusCancel := context.WithTimeout(context.Background(), time.Second*30) + defer statusCancel() - resp, err := tests.WaitUntilTxPoolEmpty(statusCtx, srv.TxnPoolOperator()) + resp, err := tests.WaitUntilTxPoolEmpty(statusCtx, srv.TxnPoolOperator()) + if err != nil { + t.Fatalf("Unable to get txpool status, %v", err) + } - if err != nil { - t.Fatalf("Unable to get txpool status, %v", err) - } + assert.Equal(t, 0, int(resp.Length)) - assert.Equal(t, 0, int(resp.Length)) + count, countErr = getCount(sender, contractAddr, client) + if countErr != nil { + t.Fatalf("Unable to call count method, %v", countErr) + } - count, countErr = getCount(sender, contractAddr, client) - if countErr != nil { - t.Fatalf("Unable to call count method, %v", countErr) + // Check that the count is correct + assert.Equalf(t, strconv.Itoa(numTransactions), count.String(), "Count doesn't match") } - // Check that the count is correct - assert.Equalf(t, strconv.Itoa(numTransactions), count.String(), "Count doesn't match") + t.Run("ECDSA", func(t *testing.T) { + runTest(t, validators.ECDSAValidatorType) + }) + + t.Run("BLS", func(t *testing.T) { + runTest(t, validators.BLSValidatorType) + }) } diff --git a/go.mod b/go.mod index b59421051a..1071740da5 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/armon/go-metrics v0.4.0 // indirect github.com/aws/aws-sdk-go v1.44.61 github.com/benbjohnson/clock v1.3.0 // indirect + github.com/coinbase/kryptology v1.8.0 github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -66,14 +67,17 @@ require ( cloud.google.com/go v0.102.0 // indirect cloud.google.com/go/compute v1.7.0 // indirect cloud.google.com/go/iam v0.3.0 // indirect + filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/bwesterb/go-ristretto v1.2.0 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect + github.com/consensys/gnark-crypto v0.5.3 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect diff --git a/go.sum b/go.sum index 3ea431f88f..3c06b7a5b6 100644 --- a/go.sum +++ b/go.sum @@ -66,7 +66,11 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw= +git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9/go.mod h1:BVJwbDfVjCjoFiKrhkei6NdGcZYpkDkdyCdg1ukytRA= github.com/0xPolygon/go-ibft v0.0.0-20220729102524-0f95a9c3a08c h1:y9Fw+byHhcrV8378z20d2WlyIoHOZiZbPIVAQ9VDuyw= github.com/0xPolygon/go-ibft v0.0.0-20220729102524-0f95a9c3a08c/go.mod h1:pXhBaK+CcHr3eUAWynKyHGTxgDwpJ3O1tvbGthN+pN4= github.com/0xPolygon/go-ibft v0.0.0-20220810095021-e43142f8d267 h1:+mFLx9IKW16fOcTKjZjkom3TGnihOuPwYAz2c6+UUWQ= @@ -137,6 +141,7 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= @@ -159,6 +164,8 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bwesterb/go-ristretto v1.2.0 h1:xxWOVbN5m8NNKiSDZXE1jtZvZnC6JSJ9cYFADiZcWtw= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= @@ -196,6 +203,11 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coinbase/kryptology v1.8.0 h1:Aoq4gdTsJhSU3lNWsD5BWmFSz2pE0GlmrljaOxepdYY= +github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= +github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.5.3 h1:4xLFGZR3NWEH2zy+YzvzHicpToQR8FXFbfLNvpGB+rE= +github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= @@ -445,6 +457,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -648,6 +661,7 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= @@ -844,6 +858,7 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUM github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= @@ -1538,6 +1553,7 @@ golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1933,6 +1949,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/helper/staking/staking.go b/helper/staking/staking.go index 45e1bce502..cfca404531 100644 --- a/helper/staking/staking.go +++ b/helper/staking/staking.go @@ -4,12 +4,12 @@ import ( "fmt" "math/big" - "github.com/0xPolygon/polygon-edge/helper/common" - "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/helper/keccak" "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" ) var ( @@ -28,14 +28,13 @@ func getAddressMapping(address types.Address, slot int64) []byte { common.PadLeftOrTrim(address.Bytes(), 32), common.PadLeftOrTrim(bigSlot.Bytes(), 32)..., ) - keccakValue := keccak.Keccak256(nil, finalSlice) - return keccakValue + return keccak.Keccak256(nil, finalSlice) } // getIndexWithOffset is a helper method for adding an offset to the already found keccak hash -func getIndexWithOffset(keccakHash []byte, offset int64) []byte { - bigOffset := big.NewInt(offset) +func getIndexWithOffset(keccakHash []byte, offset uint64) []byte { + bigOffset := big.NewInt(int64(offset)) bigKeccak := big.NewInt(0).SetBytes(keccakHash) bigKeccak.Add(bigKeccak, bigOffset) @@ -48,33 +47,85 @@ func getIndexWithOffset(keccakHash []byte, offset int64) []byte { // // It is SC dependant, and based on the SC located at: // https://github.com/0xPolygon/staking-contracts/ -func getStorageIndexes(address types.Address, index int64) *StorageIndexes { - storageIndexes := StorageIndexes{} +func getStorageIndexes(validator validators.Validator, index int) *StorageIndexes { + storageIndexes := &StorageIndexes{} + address := validator.Addr() // Get the indexes for the mappings // The index for the mapping is retrieved with: // keccak(address . slot) // . stands for concatenation (basically appending the bytes) - storageIndexes.AddressToIsValidatorIndex = getAddressMapping(address, addressToIsValidatorSlot) - storageIndexes.AddressToStakedAmountIndex = getAddressMapping(address, addressToStakedAmountSlot) - storageIndexes.AddressToValidatorIndexIndex = getAddressMapping(address, addressToValidatorIndexSlot) + storageIndexes.AddressToIsValidatorIndex = getAddressMapping( + address, + addressToIsValidatorSlot, + ) + + storageIndexes.AddressToStakedAmountIndex = getAddressMapping( + address, + addressToStakedAmountSlot, + ) + + storageIndexes.AddressToValidatorIndexIndex = getAddressMapping( + address, + addressToValidatorIndexSlot, + ) - // Get the indexes for _validators, _stakedAmount - // Index for regular types is calculated as just the regular slot - storageIndexes.StakedAmountIndex = big.NewInt(stakedAmountSlot).Bytes() + storageIndexes.ValidatorBLSPublicKeyIndex = getAddressMapping( + address, + addressToBLSPublicKeySlot, + ) // Index for array types is calculated as keccak(slot) + index // The slot for the dynamic arrays that's put in the keccak needs to be in hex form (padded 64 chars) storageIndexes.ValidatorsIndex = getIndexWithOffset( keccak.Keccak256(nil, common.PadLeftOrTrim(big.NewInt(validatorsSlot).Bytes(), 32)), - index, + uint64(index), ) - // For any dynamic array in Solidity, the size of the actual array should be - // located on slot x - storageIndexes.ValidatorsArraySizeIndex = []byte{byte(validatorsSlot)} + return storageIndexes +} + +// setBytesToStorage sets bytes data into storage map from specified base index +func setBytesToStorage( + storageMap map[types.Hash]types.Hash, + baseIndexBytes []byte, + data []byte, +) { + dataLen := len(data) + baseIndex := types.BytesToHash(baseIndexBytes) + + if dataLen <= 31 { + bytes := types.Hash{} - return &storageIndexes + copy(bytes[:len(data)], data) + + // Set 2*Size at the first byte + bytes[len(bytes)-1] = byte(dataLen * 2) + + storageMap[baseIndex] = bytes + + return + } + + // Set size at the base index + baseSlot := types.Hash{} + baseSlot[31] = byte(2*dataLen + 1) + storageMap[baseIndex] = baseSlot + + zeroIndex := keccak.Keccak256(nil, baseIndexBytes) + numBytesInSlot := 256 / 8 + + for i := 0; i < dataLen; i++ { + offset := i / numBytesInSlot + + slotIndex := types.BytesToHash(getIndexWithOffset(zeroIndex, uint64(offset))) + byteIndex := i % numBytesInSlot + + slot := storageMap[slotIndex] + slot[byteIndex] = data[i] + + storageMap[slotIndex] = slot + } } // PredeployParams contains the values used to predeploy the PoS staking contract @@ -87,11 +138,10 @@ type PredeployParams struct { // need to be modified type StorageIndexes struct { ValidatorsIndex []byte // []address - ValidatorsArraySizeIndex []byte // []address size + ValidatorBLSPublicKeyIndex []byte // mapping(address => byte[]) AddressToIsValidatorIndex []byte // mapping(address => bool) AddressToStakedAmountIndex []byte // mapping(address => uint256) AddressToValidatorIndexIndex []byte // mapping(address => uint256) - StakedAmountIndex []byte // uint256 } // Slot definitions for SC storage @@ -103,18 +153,19 @@ var ( stakedAmountSlot = int64(4) // Slot 4 minNumValidatorSlot = int64(5) // Slot 5 maxNumValidatorSlot = int64(6) // Slot 6 + addressToBLSPublicKeySlot = int64(7) // Slot 7 ) const ( DefaultStakedBalance = "0x8AC7230489E80000" // 10 ETH //nolint: lll - StakingSCBytecode = "0x6080604052600436106100f75760003560e01c80637dceceb81161008a578063e387a7ed11610059578063e387a7ed14610381578063e804fbf6146103ac578063f90ecacc146103d7578063facd743b1461041457610165565b80637dceceb8146102c3578063af6da36e14610300578063c795c0771461032b578063ca1e78191461035657610165565b8063373d6132116100c6578063373d6132146102385780633a4b66f114610263578063714ff4251461026d5780637a6eea371461029857610165565b806302b751991461016a578063065ae171146101a75780632367f6b5146101e45780632def66201461022157610165565b366101655761011b3373ffffffffffffffffffffffffffffffffffffffff16610451565b1561015b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610152906111a0565b60405180910390fd5b610163610464565b005b600080fd5b34801561017657600080fd5b50610191600480360381019061018c9190610f1e565b61053b565b60405161019e91906111fb565b60405180910390f35b3480156101b357600080fd5b506101ce60048036038101906101c99190610f1e565b610553565b6040516101db9190611125565b60405180910390f35b3480156101f057600080fd5b5061020b60048036038101906102069190610f1e565b610573565b60405161021891906111fb565b60405180910390f35b34801561022d57600080fd5b506102366105bc565b005b34801561024457600080fd5b5061024d6106a7565b60405161025a91906111fb565b60405180910390f35b61026b6106b1565b005b34801561027957600080fd5b5061028261071a565b60405161028f91906111fb565b60405180910390f35b3480156102a457600080fd5b506102ad610724565b6040516102ba91906111e0565b60405180910390f35b3480156102cf57600080fd5b506102ea60048036038101906102e59190610f1e565b610730565b6040516102f791906111fb565b60405180910390f35b34801561030c57600080fd5b50610315610748565b60405161032291906111fb565b60405180910390f35b34801561033757600080fd5b5061034061074e565b60405161034d91906111fb565b60405180910390f35b34801561036257600080fd5b5061036b610754565b6040516103789190611103565b60405180910390f35b34801561038d57600080fd5b506103966107e2565b6040516103a391906111fb565b60405180910390f35b3480156103b857600080fd5b506103c16107e8565b6040516103ce91906111fb565b60405180910390f35b3480156103e357600080fd5b506103fe60048036038101906103f99190610f4b565b6107f2565b60405161040b91906110e8565b60405180910390f35b34801561042057600080fd5b5061043b60048036038101906104369190610f1e565b610831565b6040516104489190611125565b60405180910390f35b600080823b905060008111915050919050565b34600460008282546104769190611260565b9250508190555034600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546104cc9190611260565b925050819055506104dc33610887565b156104eb576104ea336108ff565b5b3373ffffffffffffffffffffffffffffffffffffffff167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d3460405161053191906111fb565b60405180910390a2565b60036020528060005260406000206000915090505481565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6105db3373ffffffffffffffffffffffffffffffffffffffff16610451565b1561061b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610612906111a0565b60405180910390fd5b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161069d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161069490611140565b60405180910390fd5b6106a5610a4e565b565b6000600454905090565b6106d03373ffffffffffffffffffffffffffffffffffffffff16610451565b15610710576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610707906111a0565b60405180910390fd5b610718610464565b565b6000600554905090565b670de0b6b3a764000081565b60026020528060005260406000206000915090505481565b60065481565b60055481565b606060008054806020026020016040519081016040528092919081815260200182805480156107d857602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161078e575b5050505050905090565b60045481565b6000600654905090565b6000818154811061080257600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600061089282610ba0565b1580156108f85750670de0b6b3a76400006fffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b9050919050565b60065460008054905010610948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093f90611160565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060046000828254610ae991906112b6565b92505081905550610af933610ba0565b15610b0857610b0733610bf6565b5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610b4e573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7582604051610b9591906111fb565b60405180910390a250565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b60055460008054905011610c3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c36906111c0565b60405180910390fd5b600080549050600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410610cc5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cbc90611180565b60405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060006001600080549050610d1d91906112b6565b9050808214610e0b576000808281548110610d3b57610d3a6113ac565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508060008481548110610d7d57610d7c6113ac565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b6000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000805480610eba57610eb961137d565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690559055505050565b600081359050610f03816114f9565b92915050565b600081359050610f1881611510565b92915050565b600060208284031215610f3457610f336113db565b5b6000610f4284828501610ef4565b91505092915050565b600060208284031215610f6157610f606113db565b5b6000610f6f84828501610f09565b91505092915050565b6000610f848383610f90565b60208301905092915050565b610f99816112ea565b82525050565b610fa8816112ea565b82525050565b6000610fb982611226565b610fc3818561123e565b9350610fce83611216565b8060005b83811015610fff578151610fe68882610f78565b9750610ff183611231565b925050600181019050610fd2565b5085935050505092915050565b611015816112fc565b82525050565b6000611028601d8361124f565b9150611033826113e0565b602082019050919050565b600061104b60278361124f565b915061105682611409565b604082019050919050565b600061106e60128361124f565b915061107982611458565b602082019050919050565b6000611091601a8361124f565b915061109c82611481565b602082019050919050565b60006110b460408361124f565b91506110bf826114aa565b604082019050919050565b6110d381611308565b82525050565b6110e281611344565b82525050565b60006020820190506110fd6000830184610f9f565b92915050565b6000602082019050818103600083015261111d8184610fae565b905092915050565b600060208201905061113a600083018461100c565b92915050565b600060208201905081810360008301526111598161101b565b9050919050565b600060208201905081810360008301526111798161103e565b9050919050565b6000602082019050818103600083015261119981611061565b9050919050565b600060208201905081810360008301526111b981611084565b9050919050565b600060208201905081810360008301526111d9816110a7565b9050919050565b60006020820190506111f560008301846110ca565b92915050565b600060208201905061121060008301846110d9565b92915050565b6000819050602082019050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600061126b82611344565b915061127683611344565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156112ab576112aa61134e565b5b828201905092915050565b60006112c182611344565b91506112cc83611344565b9250828210156112df576112de61134e565b5b828203905092915050565b60006112f582611324565b9050919050565b60008115159050919050565b60006fffffffffffffffffffffffffffffffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b7f4f6e6c79207374616b65722063616e2063616c6c2066756e6374696f6e000000600082015250565b7f56616c696461746f72207365742068617320726561636865642066756c6c206360008201527f6170616369747900000000000000000000000000000000000000000000000000602082015250565b7f696e646578206f7574206f662072616e67650000000000000000000000000000600082015250565b7f4f6e6c7920454f412063616e2063616c6c2066756e6374696f6e000000000000600082015250565b7f56616c696461746f72732063616e2774206265206c657373207468616e20746860008201527f65206d696e696d756d2072657175697265642076616c696461746f72206e756d602082015250565b611502816112ea565b811461150d57600080fd5b50565b61151981611344565b811461152457600080fd5b5056fea26469706673582212208a8aa21d6df01384c9fc6d39a32e52ef1c0d18fd3bf9e2fca6ae1cae3d41268864736f6c63430008070033" + StakingSCBytecode = "0x6080604052600436106101185760003560e01c80637a6eea37116100a0578063d94c111b11610064578063d94c111b1461040a578063e387a7ed14610433578063e804fbf61461045e578063f90ecacc14610489578063facd743b146104c657610186565b80637a6eea37146103215780637dceceb81461034c578063af6da36e14610389578063c795c077146103b4578063ca1e7819146103df57610186565b8063373d6132116100e7578063373d6132146102595780633a4b66f1146102845780633c561f041461028e57806351a9ab32146102b9578063714ff425146102f657610186565b806302b751991461018b578063065ae171146101c85780632367f6b5146102055780632def66201461024257610186565b366101865761013c3373ffffffffffffffffffffffffffffffffffffffff16610503565b1561017c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101739061178a565b60405180910390fd5b610184610516565b005b600080fd5b34801561019757600080fd5b506101b260048036038101906101ad9190611380565b6105ed565b6040516101bf91906117e5565b60405180910390f35b3480156101d457600080fd5b506101ef60048036038101906101ea9190611380565b610605565b6040516101fc91906116ed565b60405180910390f35b34801561021157600080fd5b5061022c60048036038101906102279190611380565b610625565b60405161023991906117e5565b60405180910390f35b34801561024e57600080fd5b5061025761066e565b005b34801561026557600080fd5b5061026e610759565b60405161027b91906117e5565b60405180910390f35b61028c610763565b005b34801561029a57600080fd5b506102a36107cc565b6040516102b091906116cb565b60405180910390f35b3480156102c557600080fd5b506102e060048036038101906102db9190611380565b610972565b6040516102ed9190611708565b60405180910390f35b34801561030257600080fd5b5061030b610a12565b60405161031891906117e5565b60405180910390f35b34801561032d57600080fd5b50610336610a1c565b60405161034391906117ca565b60405180910390f35b34801561035857600080fd5b50610373600480360381019061036e9190611380565b610a28565b60405161038091906117e5565b60405180910390f35b34801561039557600080fd5b5061039e610a40565b6040516103ab91906117e5565b60405180910390f35b3480156103c057600080fd5b506103c9610a46565b6040516103d691906117e5565b60405180910390f35b3480156103eb57600080fd5b506103f4610a4c565b60405161040191906116a9565b60405180910390f35b34801561041657600080fd5b50610431600480360381019061042c91906113ad565b610ada565b005b34801561043f57600080fd5b50610448610b31565b60405161045591906117e5565b60405180910390f35b34801561046a57600080fd5b50610473610b37565b60405161048091906117e5565b60405180910390f35b34801561049557600080fd5b506104b060048036038101906104ab91906113f6565b610b41565b6040516104bd919061168e565b60405180910390f35b3480156104d257600080fd5b506104ed60048036038101906104e89190611380565b610b80565b6040516104fa91906116ed565b60405180910390f35b600080823b905060008111915050919050565b34600460008282546105289190611906565b9250508190555034600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461057e9190611906565b9250508190555061058e33610bd6565b1561059d5761059c33610c4e565b5b3373ffffffffffffffffffffffffffffffffffffffff167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d346040516105e391906117e5565b60405180910390a2565b60036020528060005260406000206000915090505481565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b61068d3373ffffffffffffffffffffffffffffffffffffffff16610503565b156106cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c49061178a565b60405180910390fd5b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541161074f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107469061172a565b60405180910390fd5b610757610d9d565b565b6000600454905090565b6107823373ffffffffffffffffffffffffffffffffffffffff16610503565b156107c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b99061178a565b60405180910390fd5b6107ca610516565b565b60606000808054905067ffffffffffffffff8111156107ee576107ed611b9e565b5b60405190808252806020026020018201604052801561082157816020015b606081526020019060019003908161080c5790505b50905060005b60008054905081101561096a576007600080838154811061084b5761084a611b6f565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080546108bb90611a36565b80601f01602080910402602001604051908101604052809291908181526020018280546108e790611a36565b80156109345780601f1061090957610100808354040283529160200191610934565b820191906000526020600020905b81548152906001019060200180831161091757829003601f168201915b505050505082828151811061094c5761094b611b6f565b5b6020026020010181905250808061096290611a99565b915050610827565b508091505090565b6007602052806000526040600020600091509050805461099190611a36565b80601f01602080910402602001604051908101604052809291908181526020018280546109bd90611a36565b8015610a0a5780601f106109df57610100808354040283529160200191610a0a565b820191906000526020600020905b8154815290600101906020018083116109ed57829003601f168201915b505050505081565b6000600554905090565b670de0b6b3a764000081565b60026020528060005260406000206000915090505481565b60065481565b60055481565b60606000805480602002602001604051908101604052809291908181526020018280548015610ad057602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610a86575b5050505050905090565b80600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209080519060200190610b2d929190611243565b5050565b60045481565b6000600654905090565b60008181548110610b5157600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000610be182610eef565b158015610c475750670de0b6b3a76400006fffffffffffffffffffffffffffffffff16600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b9050919050565b60065460008054905010610c97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8e9061174a565b60405180910390fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600080549050600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000819080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508060046000828254610e38919061195c565b92505081905550610e4833610eef565b15610e5757610e5633610f45565b5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610e9d573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f7582604051610ee491906117e5565b60405180910390a250565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b60055460008054905011610f8e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f85906117aa565b60405180910390fd5b600080549050600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161100b9061176a565b60405180910390fd5b6000600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600160008054905061106c919061195c565b905080821461115a57600080828154811061108a57611089611b6f565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905080600084815481106110cc576110cb611b6f565b5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505b6000600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600080548061120957611208611b40565b5b6001900381819060005260206000200160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690559055505050565b82805461124f90611a36565b90600052602060002090601f01602090048101928261127157600085556112b8565b82601f1061128a57805160ff19168380011785556112b8565b828001600101855582156112b8579182015b828111156112b757825182559160200191906001019061129c565b5b5090506112c591906112c9565b5090565b5b808211156112e25760008160009055506001016112ca565b5090565b60006112f96112f484611825565b611800565b90508281526020810184848401111561131557611314611bd2565b5b6113208482856119f4565b509392505050565b60008135905061133781611d0b565b92915050565b600082601f83011261135257611351611bcd565b5b81356113628482602086016112e6565b91505092915050565b60008135905061137a81611d22565b92915050565b60006020828403121561139657611395611bdc565b5b60006113a484828501611328565b91505092915050565b6000602082840312156113c3576113c2611bdc565b5b600082013567ffffffffffffffff8111156113e1576113e0611bd7565b5b6113ed8482850161133d565b91505092915050565b60006020828403121561140c5761140b611bdc565b5b600061141a8482850161136b565b91505092915050565b600061142f838361144f565b60208301905092915050565b6000611447838361154f565b905092915050565b61145881611990565b82525050565b61146781611990565b82525050565b600061147882611876565b61148281856118b1565b935061148d83611856565b8060005b838110156114be5781516114a58882611423565b97506114b083611897565b925050600181019050611491565b5085935050505092915050565b60006114d682611881565b6114e081856118c2565b9350836020820285016114f285611866565b8060005b8581101561152e578484038952815161150f858261143b565b945061151a836118a4565b925060208a019950506001810190506114f6565b50829750879550505050505092915050565b611549816119a2565b82525050565b600061155a8261188c565b61156481856118d3565b9350611574818560208601611a03565b61157d81611be1565b840191505092915050565b60006115938261188c565b61159d81856118e4565b93506115ad818560208601611a03565b6115b681611be1565b840191505092915050565b60006115ce601d836118f5565b91506115d982611bf2565b602082019050919050565b60006115f16027836118f5565b91506115fc82611c1b565b604082019050919050565b60006116146012836118f5565b915061161f82611c6a565b602082019050919050565b6000611637601a836118f5565b915061164282611c93565b602082019050919050565b600061165a6040836118f5565b915061166582611cbc565b604082019050919050565b611679816119ae565b82525050565b611688816119ea565b82525050565b60006020820190506116a3600083018461145e565b92915050565b600060208201905081810360008301526116c3818461146d565b905092915050565b600060208201905081810360008301526116e581846114cb565b905092915050565b60006020820190506117026000830184611540565b92915050565b600060208201905081810360008301526117228184611588565b905092915050565b60006020820190508181036000830152611743816115c1565b9050919050565b60006020820190508181036000830152611763816115e4565b9050919050565b6000602082019050818103600083015261178381611607565b9050919050565b600060208201905081810360008301526117a38161162a565b9050919050565b600060208201905081810360008301526117c38161164d565b9050919050565b60006020820190506117df6000830184611670565b92915050565b60006020820190506117fa600083018461167f565b92915050565b600061180a61181b565b90506118168282611a68565b919050565b6000604051905090565b600067ffffffffffffffff8211156118405761183f611b9e565b5b61184982611be1565b9050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b6000611911826119ea565b915061191c836119ea565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561195157611950611ae2565b5b828201905092915050565b6000611967826119ea565b9150611972836119ea565b92508282101561198557611984611ae2565b5b828203905092915050565b600061199b826119ca565b9050919050565b60008115159050919050565b60006fffffffffffffffffffffffffffffffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611a21578082015181840152602081019050611a06565b83811115611a30576000848401525b50505050565b60006002820490506001821680611a4e57607f821691505b60208210811415611a6257611a61611b11565b5b50919050565b611a7182611be1565b810181811067ffffffffffffffff82111715611a9057611a8f611b9e565b5b80604052505050565b6000611aa4826119ea565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611ad757611ad6611ae2565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4f6e6c79207374616b65722063616e2063616c6c2066756e6374696f6e000000600082015250565b7f56616c696461746f72207365742068617320726561636865642066756c6c206360008201527f6170616369747900000000000000000000000000000000000000000000000000602082015250565b7f696e646578206f7574206f662072616e67650000000000000000000000000000600082015250565b7f4f6e6c7920454f412063616e2063616c6c2066756e6374696f6e000000000000600082015250565b7f56616c696461746f72732063616e2774206265206c657373207468616e20746860008201527f65206d696e696d756d2072657175697265642076616c696461746f72206e756d602082015250565b611d1481611990565b8114611d1f57600080fd5b50565b611d2b816119ea565b8114611d3657600080fd5b5056fea26469706673582212201556e5927c99f1e21e8ae2bbc55b0b507bc60d9732fc9a5e25a0708b409c8c8064736f6c63430008070033" ) // PredeployStakingSC is a helper method for setting up the staking smart contract account, // using the passed in validators as pre-staked validators func PredeployStakingSC( - validators []types.Address, + vals validators.Validators, params PredeployParams, ) (*chain.GenesisAccount, error) { // Set the code for the staking smart contract @@ -138,40 +189,55 @@ func PredeployStakingSC( stakedAmount := big.NewInt(0) bigMinNumValidators := big.NewInt(int64(params.MinValidatorCount)) bigMaxNumValidators := big.NewInt(int64(params.MaxValidatorCount)) + valsLen := big.NewInt(0) + + if vals != nil { + valsLen = big.NewInt(int64(vals.Len())) + + for idx := 0; idx < vals.Len(); idx++ { + validator := vals.At(uint64(idx)) + + // Update the total staked amount + stakedAmount = stakedAmount.Add(stakedAmount, bigDefaultStakedBalance) + + // Get the storage indexes + storageIndexes := getStorageIndexes(validator, idx) + + // Set the value for the validators array + storageMap[types.BytesToHash(storageIndexes.ValidatorsIndex)] = + types.BytesToHash( + validator.Addr().Bytes(), + ) + + if blsValidator, ok := validator.(*validators.BLSValidator); ok { + setBytesToStorage( + storageMap, + storageIndexes.ValidatorBLSPublicKeyIndex, + blsValidator.BLSPublicKey, + ) + } + + // Set the value for the address -> validator array index mapping + storageMap[types.BytesToHash(storageIndexes.AddressToIsValidatorIndex)] = + types.BytesToHash(bigTrueValue.Bytes()) + + // Set the value for the address -> staked amount mapping + storageMap[types.BytesToHash(storageIndexes.AddressToStakedAmountIndex)] = + types.StringToHash(hex.EncodeBig(bigDefaultStakedBalance)) + + // Set the value for the address -> validator index mapping + storageMap[types.BytesToHash(storageIndexes.AddressToValidatorIndexIndex)] = + types.StringToHash(hex.EncodeUint64(uint64(idx))) + } + } - for indx, validator := range validators { - // Update the total staked amount - stakedAmount.Add(stakedAmount, bigDefaultStakedBalance) - - // Get the storage indexes - storageIndexes := getStorageIndexes(validator, int64(indx)) - - // Set the value for the validators array - storageMap[types.BytesToHash(storageIndexes.ValidatorsIndex)] = - types.BytesToHash( - validator.Bytes(), - ) - - // Set the value for the address -> validator array index mapping - storageMap[types.BytesToHash(storageIndexes.AddressToIsValidatorIndex)] = - types.BytesToHash(bigTrueValue.Bytes()) - - // Set the value for the address -> staked amount mapping - storageMap[types.BytesToHash(storageIndexes.AddressToStakedAmountIndex)] = - types.StringToHash(hex.EncodeBig(bigDefaultStakedBalance)) - - // Set the value for the address -> validator index mapping - storageMap[types.BytesToHash(storageIndexes.AddressToValidatorIndexIndex)] = - types.StringToHash(hex.EncodeUint64(uint64(indx))) - - // Set the value for the total staked amount - storageMap[types.BytesToHash(storageIndexes.StakedAmountIndex)] = - types.BytesToHash(stakedAmount.Bytes()) + // Set the value for the total staked amount + storageMap[types.BytesToHash(big.NewInt(stakedAmountSlot).Bytes())] = + types.BytesToHash(stakedAmount.Bytes()) - // Set the value for the size of the validators array - storageMap[types.BytesToHash(storageIndexes.ValidatorsArraySizeIndex)] = - types.StringToHash(hex.EncodeUint64(uint64(indx + 1))) - } + // Set the value for the size of the validators array + storageMap[types.BytesToHash(big.NewInt(validatorsSlot).Bytes())] = + types.BytesToHash(valsLen.Bytes()) // Set the value for the minimum number of validators storageMap[types.BytesToHash(big.NewInt(minNumValidatorSlot).Bytes())] = diff --git a/helper/tests/assert.go b/helper/tests/assert.go new file mode 100644 index 0000000000..4bdefbe25c --- /dev/null +++ b/helper/tests/assert.go @@ -0,0 +1,20 @@ +package tests + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// AssertErrorMessageContains is a helper function to make sure +// an error message matches with the expected error which is not exported +// if expected error is nil, it checks the target error is nil +func AssertErrorMessageContains(t *testing.T, expected, target error) { + t.Helper() + + if expected != nil { + assert.ErrorContains(t, target, expected.Error()) + } else { + assert.NoError(t, target) + } +} diff --git a/helper/tests/testing.go b/helper/tests/testing.go index 3c5cad4281..c502f2c9cd 100644 --- a/helper/tests/testing.go +++ b/helper/tests/testing.go @@ -31,7 +31,7 @@ var ( func GenerateKeyAndAddr(t *testing.T) (*ecdsa.PrivateKey, types.Address) { t.Helper() - key, err := crypto.GenerateKey() + key, err := crypto.GenerateECDSAKey() assert.NoError(t, err) diff --git a/jsonrpc/types.go b/jsonrpc/types.go index ad8c999a47..9755c61d6e 100644 --- a/jsonrpc/types.go +++ b/jsonrpc/types.go @@ -84,7 +84,7 @@ func toTransaction( type block struct { ParentHash types.Hash `json:"parentHash"` Sha3Uncles types.Hash `json:"sha3Uncles"` - Miner types.Address `json:"miner"` + Miner argBytes `json:"miner"` StateRoot types.Hash `json:"stateRoot"` TxRoot types.Hash `json:"transactionsRoot"` ReceiptsRoot types.Hash `json:"receiptsRoot"` @@ -109,7 +109,7 @@ func toBlock(b *types.Block, fullTx bool) *block { res := &block{ ParentHash: h.ParentHash, Sha3Uncles: h.Sha3Uncles, - Miner: h.Miner, + Miner: argBytes(h.Miner), StateRoot: h.StateRoot, TxRoot: h.TxRoot, ReceiptsRoot: h.ReceiptsRoot, diff --git a/secrets/helper/helper.go b/secrets/helper/helper.go index 0771dd5e0f..2800341eb3 100644 --- a/secrets/helper/helper.go +++ b/secrets/helper/helper.go @@ -1,37 +1,22 @@ package helper import ( - "crypto/ecdsa" "fmt" - "path/filepath" "github.com/0xPolygon/polygon-edge/crypto" - "github.com/0xPolygon/polygon-edge/helper/common" "github.com/0xPolygon/polygon-edge/network" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/awsssm" "github.com/0xPolygon/polygon-edge/secrets/gcpssm" "github.com/0xPolygon/polygon-edge/secrets/hashicorpvault" "github.com/0xPolygon/polygon-edge/secrets/local" + "github.com/0xPolygon/polygon-edge/types" "github.com/hashicorp/go-hclog" libp2pCrypto "github.com/libp2p/go-libp2p-core/crypto" ) // SetupLocalSecretsManager is a helper method for boilerplate local secrets manager setup func SetupLocalSecretsManager(dataDir string) (secrets.SecretsManager, error) { - subDirectories := []string{secrets.ConsensusFolderLocal, secrets.NetworkFolderLocal} - - // Check if the sub-directories exist / are already populated - for _, subDirectory := range subDirectories { - if common.DirectoryExists(filepath.Join(dataDir, subDirectory)) { - return nil, - fmt.Errorf( - "directory %s has previously initialized secrets data", - dataDir, - ) - } - } - return local.SecretsManagerFactory( nil, // Local secrets manager doesn't require a config &secrets.SecretsManagerParams{ @@ -79,25 +64,61 @@ func SetupGCPSSM( ) } -func InitValidatorKey(secretsManager secrets.SecretsManager) (*ecdsa.PrivateKey, error) { - // Generate the IBFT validator private key - validatorKey, validatorKeyEncoded, keyErr := crypto.GenerateAndEncodePrivateKey() - if keyErr != nil { - return nil, keyErr +// InitECDSAValidatorKey creates new ECDSA key and set as a validator key +func InitECDSAValidatorKey(secretsManager secrets.SecretsManager) (types.Address, error) { + if secretsManager.HasSecret(secrets.ValidatorKey) { + return types.ZeroAddress, fmt.Errorf(`secrets "%s" has been already initialized`, secrets.ValidatorKey) + } + + validatorKey, validatorKeyEncoded, err := crypto.GenerateAndEncodeECDSAPrivateKey() + if err != nil { + return types.ZeroAddress, err } + address := crypto.PubKeyToAddress(&validatorKey.PublicKey) + // Write the validator private key to the secrets manager storage if setErr := secretsManager.SetSecret( secrets.ValidatorKey, validatorKeyEncoded, + ); setErr != nil { + return types.ZeroAddress, setErr + } + + return address, nil +} + +func InitBLSValidatorKey(secretsManager secrets.SecretsManager) ([]byte, error) { + if secretsManager.HasSecret(secrets.ValidatorBLSKey) { + return nil, fmt.Errorf(`secrets "%s" has been already initialized`, secrets.ValidatorBLSKey) + } + + blsSecretKey, blsSecretKeyEncoded, err := crypto.GenerateAndEncodeBLSSecretKey() + if err != nil { + return nil, err + } + + // Write the validator private key to the secrets manager storage + if setErr := secretsManager.SetSecret( + secrets.ValidatorBLSKey, + blsSecretKeyEncoded, ); setErr != nil { return nil, setErr } - return validatorKey, nil + pubkeyBytes, err := crypto.BLSSecretKeyToPubkeyBytes(blsSecretKey) + if err != nil { + return nil, err + } + + return pubkeyBytes, nil } func InitNetworkingPrivateKey(secretsManager secrets.SecretsManager) (libp2pCrypto.PrivKey, error) { + if secretsManager.HasSecret(secrets.NetworkKey) { + return nil, fmt.Errorf(`secrets "%s" has been already initialized`, secrets.NetworkKey) + } + // Generate the libp2p private key libp2pKey, libp2pKeyEncoded, keyErr := network.GenerateAndEncodeLibp2pKey() if keyErr != nil { diff --git a/secrets/local/local.go b/secrets/local/local.go index a459bd8c3a..ffb4c3d4aa 100644 --- a/secrets/local/local.go +++ b/secrets/local/local.go @@ -78,6 +78,13 @@ func (l *LocalSecretsManager) Setup() error { secrets.ValidatorKeyLocal, ) + // baseDir/consensus/validator-bls.key + l.secretPathMap[secrets.ValidatorBLSKey] = filepath.Join( + l.path, + secrets.ConsensusFolderLocal, + secrets.ValidatorBLSKeyLocal, + ) + // baseDir/libp2p/libp2p.key l.secretPathMap[secrets.NetworkKey] = filepath.Join( l.path, diff --git a/secrets/local/local_test.go b/secrets/local/local_test.go index 6197fe633c..9abdcd8ae2 100644 --- a/secrets/local/local_test.go +++ b/secrets/local/local_test.go @@ -124,7 +124,7 @@ func TestLocalSecretsManager_GetSetSecret( t *testing.T, ) { // Set up the values used in the test table - validatorKey, validatorKeyEncoded, genErr := crypto.GenerateAndEncodePrivateKey() + validatorKey, validatorKeyEncoded, genErr := crypto.GenerateAndEncodeECDSAPrivateKey() if genErr != nil { t.Fatalf("Unable to generate validator private key, %v", genErr) } @@ -226,7 +226,7 @@ func TestLocalSecretsManager_GetSetSecret( func TestLocalSecretsManager_RemoveSecret(t *testing.T) { // Set up the values used in the test table - _, validatorKeyEncoded, genErr := crypto.GenerateAndEncodePrivateKey() + _, validatorKeyEncoded, genErr := crypto.GenerateAndEncodeECDSAPrivateKey() if genErr != nil { t.Fatalf("Unable to generate validator private key, %v", genErr) } diff --git a/secrets/secrets.go b/secrets/secrets.go index 982b2df5c6..4dcd30205e 100644 --- a/secrets/secrets.go +++ b/secrets/secrets.go @@ -26,14 +26,18 @@ const ( // ValidatorKey is the private key secret of the validator node ValidatorKey = "validator-key" + // ValidatorBLSKey is the bls secret key of the validator node + ValidatorBLSKey = "validator-bls-key" + // NetworkKey is the libp2p private key secret used for networking NetworkKey = "network-key" ) // Define constant file names for the local StorageManager const ( - ValidatorKeyLocal = "validator.key" - NetworkKeyLocal = "libp2p.key" + ValidatorKeyLocal = "validator.key" + ValidatorBLSKeyLocal = "validator-bls.key" + NetworkKeyLocal = "libp2p.key" ) // Define constant folder names for the local StorageManager diff --git a/state/executor.go b/state/executor.go index 744fc7dbdb..154eef8066 100644 --- a/state/executor.go +++ b/state/executor.go @@ -764,6 +764,18 @@ func (t *Transition) SetAccountDirectly(addr types.Address, account *chain.Genes return nil } +// SetCodeDirectly sets new code into the account with the specified address +// NOTE: SetCodeDirectly changes the world state without a transaction +func (t *Transition) SetCodeDirectly(addr types.Address, code []byte) error { + if !t.AccountExists(addr) { + return fmt.Errorf("account doesn't exist at %s", addr) + } + + t.state.SetCode(addr, code) + + return nil +} + func TransactionGasCost(msg *types.Transaction, isHomestead, isIstanbul bool) (uint64, error) { cost := uint64(0) diff --git a/tests/testing.go b/tests/testing.go index eb99dd8d34..e40a96b0bb 100644 --- a/tests/testing.go +++ b/tests/testing.go @@ -138,8 +138,10 @@ func stringToInt64T(t *testing.T, str string) int64 { func (e *env) ToHeader(t *testing.T) *types.Header { t.Helper() + miner := stringToAddressT(t, e.Coinbase) + return &types.Header{ - Miner: stringToAddressT(t, e.Coinbase), + Miner: miner[:], Difficulty: stringToUint64T(t, e.Difficulty), GasLimit: stringToUint64T(t, e.GasLimit), Number: stringToUint64T(t, e.Number), @@ -380,7 +382,7 @@ func (t *stTransaction) UnmarshalJSON(input []byte) error { return err } - key, err := crypto.ParsePrivateKey(secretKey) + key, err := crypto.ParseECDSAPrivateKey(secretKey) if err != nil { return fmt.Errorf("invalid private key: %w", err) } diff --git a/types/header.go b/types/header.go index 5c63cbc8e4..665e0bbc39 100644 --- a/types/header.go +++ b/types/header.go @@ -14,42 +14,42 @@ import ( // Header represents a block header in the Ethereum blockchain. type Header struct { - ParentHash Hash `json:"parentHash"` - Sha3Uncles Hash `json:"sha3Uncles"` - Miner Address `json:"miner"` - StateRoot Hash `json:"stateRoot"` - TxRoot Hash `json:"transactionsRoot"` - ReceiptsRoot Hash `json:"receiptsRoot"` - LogsBloom Bloom `json:"logsBloom"` - Difficulty uint64 `json:"difficulty"` - Number uint64 `json:"number"` - GasLimit uint64 `json:"gasLimit"` - GasUsed uint64 `json:"gasUsed"` - Timestamp uint64 `json:"timestamp"` - ExtraData []byte `json:"extraData"` - MixHash Hash `json:"mixHash"` - Nonce Nonce `json:"nonce"` - Hash Hash `json:"hash"` + ParentHash Hash `json:"parentHash"` + Sha3Uncles Hash `json:"sha3Uncles"` + Miner []byte `json:"miner"` + StateRoot Hash `json:"stateRoot"` + TxRoot Hash `json:"transactionsRoot"` + ReceiptsRoot Hash `json:"receiptsRoot"` + LogsBloom Bloom `json:"logsBloom"` + Difficulty uint64 `json:"difficulty"` + Number uint64 `json:"number"` + GasLimit uint64 `json:"gasLimit"` + GasUsed uint64 `json:"gasUsed"` + Timestamp uint64 `json:"timestamp"` + ExtraData []byte `json:"extraData"` + MixHash Hash `json:"mixHash"` + Nonce Nonce `json:"nonce"` + Hash Hash `json:"hash"` } // headerJSON represents a block header used for json calls type headerJSON struct { - ParentHash Hash `json:"parentHash"` - Sha3Uncles Hash `json:"sha3Uncles"` - Miner Address `json:"miner"` - StateRoot Hash `json:"stateRoot"` - TxRoot Hash `json:"transactionsRoot"` - ReceiptsRoot Hash `json:"receiptsRoot"` - LogsBloom Bloom `json:"logsBloom"` - Difficulty string `json:"difficulty"` - Number string `json:"number"` - GasLimit string `json:"gasLimit"` - GasUsed string `json:"gasUsed"` - Timestamp string `json:"timestamp"` - ExtraData string `json:"extraData"` - MixHash Hash `json:"mixHash"` - Nonce Nonce `json:"nonce"` - Hash Hash `json:"hash"` + ParentHash Hash `json:"parentHash"` + Sha3Uncles Hash `json:"sha3Uncles"` + Miner string `json:"miner"` + StateRoot Hash `json:"stateRoot"` + TxRoot Hash `json:"transactionsRoot"` + ReceiptsRoot Hash `json:"receiptsRoot"` + LogsBloom Bloom `json:"logsBloom"` + Difficulty string `json:"difficulty"` + Number string `json:"number"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` + Timestamp string `json:"timestamp"` + ExtraData string `json:"extraData"` + MixHash Hash `json:"mixHash"` + Nonce Nonce `json:"nonce"` + Hash Hash `json:"hash"` } func (h *Header) MarshalJSON() ([]byte, error) { @@ -57,7 +57,7 @@ func (h *Header) MarshalJSON() ([]byte, error) { header.ParentHash = h.ParentHash header.Sha3Uncles = h.Sha3Uncles - header.Miner = h.Miner + header.Miner = hex.EncodeToHex(h.Miner) header.StateRoot = h.StateRoot header.TxRoot = h.TxRoot header.ReceiptsRoot = h.ReceiptsRoot @@ -85,7 +85,6 @@ func (h *Header) UnmarshalJSON(input []byte) error { h.ParentHash = header.ParentHash h.Sha3Uncles = header.Sha3Uncles - h.Miner = header.Miner h.StateRoot = header.StateRoot h.TxRoot = header.TxRoot h.ReceiptsRoot = header.ReceiptsRoot @@ -96,6 +95,10 @@ func (h *Header) UnmarshalJSON(input []byte) error { var err error + if h.Miner, err = hex.DecodeHex(header.Miner); err != nil { + return err + } + if h.Difficulty, err = hex.DecodeUint64(header.Difficulty); err != nil { return err } @@ -139,6 +142,10 @@ func (h *Header) SetNonce(i uint64) { binary.BigEndian.PutUint64(h.Nonce[:], i) } +func (h *Header) IsGenesis() bool { + return h.Hash != ZeroHash && h.Number == 0 +} + type Nonce [8]byte func (n Nonce) String() string { @@ -185,7 +192,6 @@ func (h *Header) Copy() *Header { newHeader := &Header{ ParentHash: h.ParentHash, Sha3Uncles: h.Sha3Uncles, - Miner: h.Miner, StateRoot: h.StateRoot, TxRoot: h.TxRoot, ReceiptsRoot: h.ReceiptsRoot, @@ -200,6 +206,9 @@ func (h *Header) Copy() *Header { Timestamp: h.Timestamp, } + newHeader.Miner = make([]byte, len(h.Miner)) + copy(newHeader.Miner[:], h.Miner[:]) + newHeader.ExtraData = make([]byte, len(h.ExtraData)) copy(newHeader.ExtraData[:], h.ExtraData[:]) diff --git a/types/header_test.go b/types/header_test.go index 78b540d9bd..79df510f4d 100644 --- a/types/header_test.go +++ b/types/header_test.go @@ -36,7 +36,7 @@ func TestHeader_JSON(t *testing.T) { header = Header{ ParentHash: Hash{0x1}, Sha3Uncles: Hash{0x2}, - Miner: Address{0x1}, + Miner: Address{0x1}.Bytes(), StateRoot: Hash{0x4}, TxRoot: Hash{0x5}, ReceiptsRoot: Hash{0x6}, diff --git a/types/rlp_marshal.go b/types/rlp_marshal.go index 011d4d4a2e..0b1a50ae59 100644 --- a/types/rlp_marshal.go +++ b/types/rlp_marshal.go @@ -67,7 +67,7 @@ func (h *Header) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { vv.Set(arena.NewBytes(h.ParentHash.Bytes())) vv.Set(arena.NewBytes(h.Sha3Uncles.Bytes())) - vv.Set(arena.NewBytes(h.Miner.Bytes())) + vv.Set(arena.NewCopyBytes(h.Miner[:])) vv.Set(arena.NewBytes(h.StateRoot.Bytes())) vv.Set(arena.NewBytes(h.TxRoot.Bytes())) vv.Set(arena.NewBytes(h.ReceiptsRoot.Bytes())) @@ -110,6 +110,7 @@ func (r *Receipt) MarshalRLPTo(dst []byte) []byte { // MarshalRLPWith marshals a receipt with a specific fastrlp.Arena func (r *Receipt) MarshalRLPWith(a *fastrlp.Arena) *fastrlp.Value { vv := a.NewArray() + if r.Status != nil { vv.Set(a.NewUint(uint64(*r.Status))) } else { diff --git a/types/rlp_unmarshal.go b/types/rlp_unmarshal.go index 31408d183e..dac99580cc 100644 --- a/types/rlp_unmarshal.go +++ b/types/rlp_unmarshal.go @@ -110,7 +110,7 @@ func (h *Header) UnmarshalRLPFrom(p *fastrlp.Parser, v *fastrlp.Value) error { return err } // miner - if err = elems[2].GetAddr(h.Miner[:]); err != nil { + if h.Miner, err = elems[2].GetBytes(h.Miner[:]); err != nil { return err } // stateroot diff --git a/validators/bls.go b/validators/bls.go new file mode 100644 index 0000000000..827f7613e1 --- /dev/null +++ b/validators/bls.go @@ -0,0 +1,136 @@ +package validators + +import ( + "bytes" + "errors" + "fmt" + + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/fastrlp" +) + +var ( + ErrInvalidTypeAssert = errors.New("invalid type assert") +) + +type BLSValidatorPublicKey []byte + +// String returns a public key in hex +func (k BLSValidatorPublicKey) String() string { + return hex.EncodeToHex(k[:]) +} + +// MarshalText implements encoding.TextMarshaler +func (k BLSValidatorPublicKey) MarshalText() ([]byte, error) { + return []byte(k.String()), nil +} + +// UnmarshalText parses an BLS Public Key in hex +func (k *BLSValidatorPublicKey) UnmarshalText(input []byte) error { + kk, err := hex.DecodeHex(string(input)) + if err != nil { + return err + } + + *k = kk + + return nil +} + +// BLSValidator is a validator using BLS signing algorithm +type BLSValidator struct { + Address types.Address + BLSPublicKey BLSValidatorPublicKey +} + +// NewBLSValidator is a constructor of BLSValidator +func NewBLSValidator(addr types.Address, blsPubkey []byte) *BLSValidator { + return &BLSValidator{ + Address: addr, + BLSPublicKey: blsPubkey, + } +} + +// Type returns the ValidatorType of BLSValidator +func (v *BLSValidator) Type() ValidatorType { + return BLSValidatorType +} + +// String returns string representation of BLSValidator +// Format => [Address]:[BLSPublicKey] +func (v *BLSValidator) String() string { + return fmt.Sprintf( + "%s:%s", + v.Address.String(), + hex.EncodeToHex(v.BLSPublicKey), + ) +} + +// Addr returns the validator address +func (v *BLSValidator) Addr() types.Address { + return v.Address +} + +// Copy returns copy of BLS Validator +func (v *BLSValidator) Copy() Validator { + pubkey := make([]byte, len(v.BLSPublicKey)) + copy(pubkey, v.BLSPublicKey) + + return &BLSValidator{ + Address: v.Address, + BLSPublicKey: pubkey, + } +} + +// Equal checks the given validator matches with its data +func (v *BLSValidator) Equal(vr Validator) bool { + vv, ok := vr.(*BLSValidator) + if !ok { + return false + } + + return v.Address == vv.Address && bytes.Equal(v.BLSPublicKey, vv.BLSPublicKey) +} + +// MarshalRLPWith is a RLP Marshaller +func (v *BLSValidator) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { + vv := arena.NewArray() + + vv.Set(arena.NewBytes(v.Address.Bytes())) + vv.Set(arena.NewCopyBytes(v.BLSPublicKey)) + + return vv +} + +// UnmarshalRLPFrom is a RLP Unmarshaller +func (v *BLSValidator) UnmarshalRLPFrom(p *fastrlp.Parser, val *fastrlp.Value) error { + elems, err := val.GetElems() + if err != nil { + return err + } + + if len(elems) < 2 { + return fmt.Errorf("incorrect number of elements to decode BLSValidator, expected 2 but found %d", len(elems)) + } + + if err := elems[0].GetAddr(v.Address[:]); err != nil { + return fmt.Errorf("failed to decode Address: %w", err) + } + + if v.BLSPublicKey, err = elems[1].GetBytes(v.BLSPublicKey); err != nil { + return fmt.Errorf("failed to decode BLSPublicKey: %w", err) + } + + return nil +} + +// Bytes returns bytes of BLSValidator in RLP encode +func (v *BLSValidator) Bytes() []byte { + return types.MarshalRLPTo(v.MarshalRLPWith, nil) +} + +// SetFromBytes parses given bytes in RLP encode and map to its fields +func (v *BLSValidator) SetFromBytes(input []byte) error { + return types.UnmarshalRlp(v.UnmarshalRLPFrom, input) +} diff --git a/validators/bls_test.go b/validators/bls_test.go new file mode 100644 index 0000000000..6abbb3f14a --- /dev/null +++ b/validators/bls_test.go @@ -0,0 +1,211 @@ +package validators + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/0xPolygon/polygon-edge/helper/hex" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +func TestBLSValidatorPublicKeyString(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + hex.EncodeToHex([]byte(testBLSPubKey1)), + testBLSPubKey1.String(), + ) +} + +func TestBLSValidatorPublicKeyMarshal(t *testing.T) { + t.Parallel() + + res, err := json.Marshal(testBLSPubKey1) + + assert.NoError(t, err) + assert.Equal( + t, + hex.EncodeToHex([]byte(testBLSPubKey1)), + strings.Trim( + // remove double quotes in json + string(res), + "\"", + ), + ) +} + +func TestBLSValidatorPublicKeyUnmarshal(t *testing.T) { + t.Parallel() + + key := BLSValidatorPublicKey{} + + err := json.Unmarshal( + []byte( + fmt.Sprintf("\"%s\"", hex.EncodeToHex(testBLSPubKey2)), + ), + &key, + ) + + assert.NoError(t, err) + assert.Equal( + t, + testBLSPubKey2, + key, + ) +} + +func TestNewBLSValidator(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + &BLSValidator{addr1, testBLSPubKey1}, + NewBLSValidator(addr1, testBLSPubKey1), + ) +} + +func TestBLSValidatorType(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + BLSValidatorType, + NewBLSValidator(addr1, testBLSPubKey1).Type(), + ) +} + +func TestBLSValidatorString(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + fmt.Sprintf( + "%s:%s", + addr1.String(), + "0x"+hex.EncodeToString(testBLSPubKey1), + ), + NewBLSValidator(addr1, testBLSPubKey1).String(), + ) +} + +func TestBLSValidatorAddr(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + addr1, + NewBLSValidator(addr1, testBLSPubKey1).Addr(), + ) +} + +func TestBLSValidatorCopy(t *testing.T) { + t.Parallel() + + v1 := NewBLSValidator(addr1, testBLSPubKey1) + v2 := v1.Copy() + + assert.Equal(t, v1, v2) + + // check the addresses are different + typedV2, ok := v2.(*BLSValidator) + + assert.True(t, ok) + assert.NotSame(t, v1.Address, typedV2.Address) + assert.NotSame(t, v1.BLSPublicKey, typedV2.BLSPublicKey) +} + +func TestBLSValidatorEqual(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + val1 *BLSValidator + val2 *BLSValidator + expected bool + }{ + { + name: "equal", + val1: NewBLSValidator(addr1, testBLSPubKey1), + val2: NewBLSValidator(addr1, testBLSPubKey1), + expected: true, + }, + { + name: "addr does not equal", + val1: NewBLSValidator(addr1, testBLSPubKey1), + val2: NewBLSValidator(addr2, testBLSPubKey1), + expected: false, + }, + { + name: "public key does not equal", + val1: NewBLSValidator(addr1, testBLSPubKey1), + val2: NewBLSValidator(addr1, testBLSPubKey2), + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.val1.Equal(test.val2), + ) + }) + } +} + +func TestBLSValidatorMarshalAndUnmarshal(t *testing.T) { + t.Parallel() + + val1 := NewBLSValidator(addr1, testBLSPubKey1) + + marshalRes := types.MarshalRLPTo(val1.MarshalRLPWith, nil) + + val2 := new(BLSValidator) + + assert.NoError( + t, + types.UnmarshalRlp(val2.UnmarshalRLPFrom, marshalRes), + ) + + assert.Equal(t, val1, val2) +} + +func TestBLSValidatorBytes(t *testing.T) { + t.Parallel() + + val := NewBLSValidator(addr1, testBLSPubKey1) + + // result of Bytes() equals the data encoded in RLP + assert.Equal( + t, + types.MarshalRLPTo(val.MarshalRLPWith, nil), + val.Bytes(), + ) +} + +func TestBLSValidatorFromBytes(t *testing.T) { + t.Parallel() + + val1 := NewBLSValidator(addr1, testBLSPubKey1) + marshalledData := types.MarshalRLPTo(val1.MarshalRLPWith, nil) + + val2 := new(BLSValidator) + + // SetFromBytes reads RLP encoded data + assert.NoError(t, val2.SetFromBytes(marshalledData)) + + assert.Equal( + t, + val1, + val2, + ) +} diff --git a/validators/ecdsa.go b/validators/ecdsa.go new file mode 100644 index 0000000000..1ec1a5b8bd --- /dev/null +++ b/validators/ecdsa.go @@ -0,0 +1,72 @@ +package validators + +import ( + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/fastrlp" +) + +// BLSValidator is a validator using ECDSA signing algorithm +type ECDSAValidator struct { + Address types.Address +} + +// NewECDSAValidator is a constructor of ECDSAValidator +func NewECDSAValidator(addr types.Address) *ECDSAValidator { + return &ECDSAValidator{ + Address: addr, + } +} + +// Type returns the ValidatorType of ECDSAValidator +func (v *ECDSAValidator) Type() ValidatorType { + return ECDSAValidatorType +} + +// String returns string representation of ECDSAValidator +func (v *ECDSAValidator) String() string { + return v.Address.String() +} + +// Addr returns the validator address +func (v *ECDSAValidator) Addr() types.Address { + return v.Address +} + +// Copy returns copy of ECDSAValidator +func (v *ECDSAValidator) Copy() Validator { + return &ECDSAValidator{ + Address: v.Address, + } +} + +// Equal checks the given validator matches with its data +func (v *ECDSAValidator) Equal(vr Validator) bool { + vv, ok := vr.(*ECDSAValidator) + if !ok { + return false + } + + return v.Address == vv.Address +} + +// MarshalRLPWith is a RLP Marshaller +func (v *ECDSAValidator) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { + return arena.NewBytes(v.Address.Bytes()) +} + +// UnmarshalRLPFrom is a RLP Unmarshaller +func (v *ECDSAValidator) UnmarshalRLPFrom(p *fastrlp.Parser, val *fastrlp.Value) error { + return val.GetAddr(v.Address[:]) +} + +// Bytes returns bytes of ECDSAValidator +func (v *ECDSAValidator) Bytes() []byte { + return v.Address.Bytes() +} + +// SetFromBytes parses given bytes +func (v *ECDSAValidator) SetFromBytes(input []byte) error { + v.Address = types.BytesToAddress(input) + + return nil +} diff --git a/validators/ecdsa_test.go b/validators/ecdsa_test.go new file mode 100644 index 0000000000..399c8c6e69 --- /dev/null +++ b/validators/ecdsa_test.go @@ -0,0 +1,150 @@ +package validators + +import ( + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +func TestNewECDSAValidator(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + &ECDSAValidator{addr1}, + NewECDSAValidator(addr1), + ) +} + +func TestECDSAValidatorType(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + ECDSAValidatorType, + NewECDSAValidator(addr1).Type(), + ) +} + +func TestECDSAValidatorString(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + addr1.String(), + NewECDSAValidator(addr1).String(), + ) +} + +func TestECDSAValidatorAddr(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + addr1, + NewECDSAValidator(addr1).Addr(), + ) +} + +func TestECDSAValidatorCopy(t *testing.T) { + t.Parallel() + + v1 := NewECDSAValidator(addr1) + + v2 := v1.Copy() + + assert.Equal(t, v1, v2) + + // check the addresses are different + typedV2, ok := v2.(*ECDSAValidator) + + assert.True(t, ok) + assert.NotSame(t, v1.Address, typedV2.Address) +} + +func TestECDSAValidatorEqual(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + val1 *ECDSAValidator + val2 *ECDSAValidator + expected bool + }{ + { + name: "equal", + val1: NewECDSAValidator(addr1), + val2: NewECDSAValidator(addr1), + expected: true, + }, + { + name: "not equal", + val1: NewECDSAValidator(addr1), + val2: NewECDSAValidator(addr2), + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.val1.Equal(test.val2), + ) + }) + } +} + +func TestECDSAValidatorMarshalAndUnmarshal(t *testing.T) { + t.Parallel() + + val1 := NewECDSAValidator(addr1) + + marshalRes := types.MarshalRLPTo(val1.MarshalRLPWith, nil) + + val2 := new(ECDSAValidator) + + assert.NoError( + t, + types.UnmarshalRlp(val2.UnmarshalRLPFrom, marshalRes), + ) + + assert.Equal(t, val1, val2) +} + +func TestECDSAValidatorBytes(t *testing.T) { + t.Parallel() + + val := NewECDSAValidator(addr1) + + // result of Bytes() equals the data encoded in RLP + assert.Equal( + t, + val.Address.Bytes(), + val.Bytes(), + ) +} + +func TestECDSAValidatorFromBytes(t *testing.T) { + t.Parallel() + + val1 := NewECDSAValidator(addr1) + marshalledData := types.MarshalRLPTo(val1.MarshalRLPWith, nil) + + val2 := new(ECDSAValidator) + + // SetFromBytes reads RLP encoded data + assert.NoError(t, val2.SetFromBytes(marshalledData)) + + assert.Equal( + t, + val1, + val2, + ) +} diff --git a/validators/helper.go b/validators/helper.go new file mode 100644 index 0000000000..a00c0368c6 --- /dev/null +++ b/validators/helper.go @@ -0,0 +1,131 @@ +package validators + +import ( + "encoding/hex" + "errors" + "fmt" + "strings" + + "github.com/0xPolygon/polygon-edge/types" +) + +var ( + ErrInvalidBLSValidatorFormat = errors.New("invalid validator format, expected [Validator Address]:[BLS Public Key]") +) + +// NewValidatorFromType instantiates a validator by specified type +func NewValidatorFromType(t ValidatorType) (Validator, error) { + switch t { + case ECDSAValidatorType: + return new(ECDSAValidator), nil + case BLSValidatorType: + return new(BLSValidator), nil + } + + return nil, ErrInvalidValidatorType +} + +// NewValidatorSetFromType instantiates a validators by specified type +func NewValidatorSetFromType(t ValidatorType) Validators { + switch t { + case ECDSAValidatorType: + return NewECDSAValidatorSet() + case BLSValidatorType: + return NewBLSValidatorSet() + } + + return nil +} + +// NewECDSAValidatorSet creates Validator Set for ECDSAValidator with initialized validators +func NewECDSAValidatorSet(ecdsaValidators ...*ECDSAValidator) Validators { + validators := make([]Validator, len(ecdsaValidators)) + + for idx, val := range ecdsaValidators { + validators[idx] = Validator(val) + } + + return &Set{ + ValidatorType: ECDSAValidatorType, + Validators: validators, + } +} + +// NewBLSValidatorSet creates Validator Set for BLSValidator with initialized validators +func NewBLSValidatorSet(blsValidators ...*BLSValidator) Validators { + validators := make([]Validator, len(blsValidators)) + + for idx, val := range blsValidators { + validators[idx] = Validator(val) + } + + return &Set{ + ValidatorType: BLSValidatorType, + Validators: validators, + } +} + +// ParseValidator parses a validator represented in string +func ParseValidator(validatorType ValidatorType, validator string) (Validator, error) { + switch validatorType { + case ECDSAValidatorType: + return ParseECDSAValidator(validator), nil + case BLSValidatorType: + return ParseBLSValidator(validator) + default: + // shouldn't reach here + return nil, fmt.Errorf("invalid validator type: %s", validatorType) + } +} + +// ParseValidator parses an array of validator represented in string +func ParseValidators(validatorType ValidatorType, rawValidators []string) (Validators, error) { + set := NewValidatorSetFromType(validatorType) + if set == nil { + return nil, fmt.Errorf("invalid validator type: %s", validatorType) + } + + for _, s := range rawValidators { + validator, err := ParseValidator(validatorType, s) + if err != nil { + return nil, err + } + + if err := set.Add(validator); err != nil { + return nil, err + } + } + + return set, nil +} + +// ParseBLSValidator parses ECDSAValidator represented in string +func ParseECDSAValidator(validator string) *ECDSAValidator { + return &ECDSAValidator{ + Address: types.StringToAddress(validator), + } +} + +// ParseBLSValidator parses BLSValidator represented in string +func ParseBLSValidator(validator string) (*BLSValidator, error) { + subValues := strings.Split(validator, ":") + + if len(subValues) != 2 { + return nil, ErrInvalidBLSValidatorFormat + } + + addrBytes, err := hex.DecodeString(strings.TrimPrefix(subValues[0], "0x")) + if err != nil { + return nil, fmt.Errorf("failed to parse address: %w", err) + } + + pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(subValues[1], "0x")) + if err != nil { + return nil, fmt.Errorf("failed to parse BLS Public Key: %w", err) + } + + return &BLSValidator{ + Address: types.BytesToAddress(addrBytes), + BLSPublicKey: pubKeyBytes, + }, nil +} diff --git a/validators/helper_test.go b/validators/helper_test.go new file mode 100644 index 0000000000..341368da48 --- /dev/null +++ b/validators/helper_test.go @@ -0,0 +1,319 @@ +package validators + +import ( + "encoding/hex" + "errors" + "fmt" + "testing" + + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +var ( + addr1 = types.StringToAddress("1") + addr2 = types.StringToAddress("2") + testBLSPubKey1 = BLSValidatorPublicKey([]byte("bls_pubkey1")) + testBLSPubKey2 = BLSValidatorPublicKey([]byte("bls_pubkey2")) + + ecdsaValidator1 = NewECDSAValidator(addr1) + ecdsaValidator2 = NewECDSAValidator(addr2) + blsValidator1 = NewBLSValidator(addr1, testBLSPubKey1) + blsValidator2 = NewBLSValidator(addr2, testBLSPubKey2) + + fakeValidatorType = ValidatorType("fake") +) + +func createTestBLSValidatorString( + addr types.Address, + blsPubKey []byte, +) string { + return fmt.Sprintf( + "%s:%s", + addr.String(), + "0x"+hex.EncodeToString(blsPubKey), + ) +} + +func TestNewValidatorFromType(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validatorType ValidatorType + expected Validator + err error + }{ + { + name: "ECDSAValidator", + validatorType: ECDSAValidatorType, + expected: new(ECDSAValidator), + err: nil, + }, + { + name: "BLSValidator", + validatorType: BLSValidatorType, + expected: new(BLSValidator), + err: nil, + }, + { + name: "undefined type", + validatorType: fakeValidatorType, + expected: nil, + err: ErrInvalidValidatorType, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := NewValidatorFromType(test.validatorType) + + assert.Equal( + t, + test.expected, + res, + ) + + assert.ErrorIs( + t, + test.err, + err, + ) + }) + } +} + +func TestNewValidatorSetFromType(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validatorType ValidatorType + expected Validators + }{ + { + name: "ECDSAValidators", + validatorType: ECDSAValidatorType, + expected: &Set{ + ValidatorType: ECDSAValidatorType, + Validators: []Validator{}, + }, + }, + { + name: "BLSValidators", + validatorType: BLSValidatorType, + expected: &Set{ + ValidatorType: BLSValidatorType, + Validators: []Validator{}, + }, + }, + { + name: "undefined type", + validatorType: fakeValidatorType, + expected: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + NewValidatorSetFromType(test.validatorType), + ) + }) + } +} + +func TestParseValidator(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + // inputs + validatorType ValidatorType + validatorStr string + // outputs + expectedValidator Validator + expectedErr error + }{ + { + name: "ECDSAValidator", + validatorType: ECDSAValidatorType, + validatorStr: addr1.String(), + expectedValidator: ecdsaValidator1, + expectedErr: nil, + }, + { + name: "BLSValidator", + validatorType: BLSValidatorType, + validatorStr: createTestBLSValidatorString(addr1, testBLSPubKey1), + expectedValidator: blsValidator1, + expectedErr: nil, + }, + { + name: "undefined type", + validatorType: fakeValidatorType, + validatorStr: addr1.String(), + expectedValidator: nil, + expectedErr: fmt.Errorf("invalid validator type: %s", fakeValidatorType), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + val, err := ParseValidator( + test.validatorType, + test.validatorStr, + ) + + assert.Equal(t, test.expectedValidator, val) + + assert.Equal(t, test.expectedErr, err) + }) + } +} + +func TestParseValidators(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + // inputs + validatorType ValidatorType + validatorStrs []string + // outputs + expectedValidators Validators + expectedErr error + }{ + { + name: "ECDSAValidator", + validatorType: ECDSAValidatorType, + validatorStrs: []string{ + addr1.String(), + addr2.String(), + }, + expectedValidators: NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + expectedErr: nil, + }, + { + name: "BLSValidator", + validatorType: BLSValidatorType, + validatorStrs: []string{ + createTestBLSValidatorString(addr1, testBLSPubKey1), + createTestBLSValidatorString(addr2, testBLSPubKey2), + }, + expectedValidators: NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + expectedErr: nil, + }, + { + name: "undefined type", + validatorType: fakeValidatorType, + validatorStrs: []string{ + createTestBLSValidatorString(addr1, testBLSPubKey1), + createTestBLSValidatorString(addr2, testBLSPubKey2), + }, + expectedValidators: nil, + expectedErr: fmt.Errorf("invalid validator type: %s", fakeValidatorType), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + vals, err := ParseValidators( + test.validatorType, + test.validatorStrs, + ) + + assert.Equal(t, test.expectedValidators, vals) + + assert.Equal(t, test.expectedErr, err) + }) + } +} + +func TestParseECDSAValidator(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + ecdsaValidator1, + ParseECDSAValidator(addr1.String()), + ) +} + +func TestParseBLSValidator(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + // inputs + validatorStr string + // outputs + expectedValidator *BLSValidator + expectedErr error + }{ + { + name: "should parse correctly", + validatorStr: createTestBLSValidatorString(addr1, testBLSPubKey1), + expectedValidator: blsValidator1, + expectedErr: nil, + }, + { + name: "should return error for incorrect format", + validatorStr: addr1.String(), + expectedValidator: nil, + expectedErr: ErrInvalidBLSValidatorFormat, + }, + { + name: "should return error for incorrect Address format", + validatorStr: fmt.Sprintf("%s:%s", "aaaaa", testBLSPubKey1.String()), + expectedValidator: nil, + expectedErr: errors.New("failed to parse address:"), + }, + { + name: "should return for incorrect BLS Public Key format", + validatorStr: fmt.Sprintf("%s:%s", addr1.String(), "bbbbb"), + expectedValidator: nil, + expectedErr: errors.New("failed to parse BLS Public Key:"), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + val, err := ParseBLSValidator( + test.validatorStr, + ) + + assert.Equal(t, test.expectedValidator, val) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} diff --git a/validators/json_test.go b/validators/json_test.go new file mode 100644 index 0000000000..a7d0ccfa7c --- /dev/null +++ b/validators/json_test.go @@ -0,0 +1,155 @@ +package validators + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestECDSAValidatorsMarshalJSON(t *testing.T) { + t.Parallel() + + validators := &Set{ + ValidatorType: ECDSAValidatorType, + Validators: []Validator{ + &ECDSAValidator{addr1}, + &ECDSAValidator{addr2}, + }, + } + + res, err := json.Marshal(validators) + + assert.NoError(t, err) + + assert.JSONEq( + t, + fmt.Sprintf( + `[ + { + "Address": "%s" + }, + { + "Address": "%s" + } + ]`, + addr1.String(), + addr2.String(), + ), + string(res), + ) +} + +func TestECDSAValidatorsUnmarshalJSON(t *testing.T) { + t.Parallel() + + inputStr := fmt.Sprintf( + `[ + { + "Address": "%s" + }, + { + "Address": "%s" + } + ]`, + addr1.String(), + addr2.String(), + ) + + validators := NewECDSAValidatorSet() + + assert.NoError( + t, + json.Unmarshal([]byte(inputStr), validators), + ) + + assert.Equal( + t, + &Set{ + ValidatorType: ECDSAValidatorType, + Validators: []Validator{ + &ECDSAValidator{addr1}, + &ECDSAValidator{addr2}, + }, + }, + validators, + ) +} + +func TestBLSValidatorsMarshalJSON(t *testing.T) { + t.Parallel() + + validators := &Set{ + ValidatorType: BLSValidatorType, + Validators: []Validator{ + &BLSValidator{addr1, testBLSPubKey1}, + &BLSValidator{addr2, testBLSPubKey2}, + }, + } + + res, err := json.Marshal(validators) + + assert.NoError(t, err) + + assert.JSONEq( + t, + fmt.Sprintf( + `[ + { + "Address": "%s", + "BLSPublicKey": "%s" + }, + { + "Address": "%s", + "BLSPublicKey": "%s" + } + ]`, + addr1, + testBLSPubKey1, + addr2, + testBLSPubKey2, + ), + string(res), + ) +} + +func TestBLSValidatorsUnmarshalJSON(t *testing.T) { + t.Parallel() + + inputStr := fmt.Sprintf( + `[ + { + "Address": "%s", + "BLSPublicKey": "%s" + }, + { + "Address": "%s", + "BLSPublicKey": "%s" + } + ]`, + addr1, + testBLSPubKey1, + addr2, + testBLSPubKey2, + ) + + validators := NewBLSValidatorSet() + + assert.NoError( + t, + json.Unmarshal([]byte(inputStr), validators), + ) + + assert.Equal( + t, + &Set{ + ValidatorType: BLSValidatorType, + Validators: []Validator{ + &BLSValidator{addr1, testBLSPubKey1}, + &BLSValidator{addr2, testBLSPubKey2}, + }, + }, + validators, + ) +} diff --git a/validators/set.go b/validators/set.go new file mode 100644 index 0000000000..c7cc99f57e --- /dev/null +++ b/validators/set.go @@ -0,0 +1,200 @@ +package validators + +import ( + "encoding/json" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/fastrlp" +) + +type Set struct { + ValidatorType ValidatorType + Validators []Validator +} + +// Type returns the type of validator +func (s *Set) Type() ValidatorType { + return s.ValidatorType +} + +// Len returns the size of its collection +func (s *Set) Len() int { + return len(s.Validators) +} + +// Equal checks the given validators matches with its data +func (s *Set) Equal(ss Validators) bool { + if s.ValidatorType != ss.Type() { + return false + } + + if s.Len() != ss.Len() { + return false + } + + for idx := 0; idx < s.Len(); idx++ { + val1 := s.At(uint64(idx)) + val2 := ss.At(uint64(idx)) + + if !val1.Equal(val2) { + return false + } + } + + return true +} + +// Copy returns a copy of BLSValidators +func (s *Set) Copy() Validators { + cloneValidators := make([]Validator, len(s.Validators)) + + for idx, val := range s.Validators { + cloneValidators[idx] = val.Copy() + } + + return &Set{ + ValidatorType: s.ValidatorType, + Validators: cloneValidators, + } +} + +// At returns a validator at specified index in the collection +func (s *Set) At(index uint64) Validator { + return s.Validators[index] +} + +// Index returns the index of the validator whose address matches with the given address +func (s *Set) Index(addr types.Address) int64 { + for i, val := range s.Validators { + if val.Addr() == addr { + return int64(i) + } + } + + return -1 +} + +// Includes return the bool indicating whether the validator +// whose address matches with the given address exists or not +func (s *Set) Includes(addr types.Address) bool { + return s.Index(addr) != -1 +} + +// Add adds a validator into the collection +func (s *Set) Add(val Validator) error { + if s.ValidatorType != val.Type() { + return ErrMismatchValidatorType + } + + if s.Includes(val.Addr()) { + return ErrValidatorAlreadyExists + } + + s.Validators = append(s.Validators, val) + + return nil +} + +// Del removes a validator from the collection +func (s *Set) Del(val Validator) error { + if s.ValidatorType != val.Type() { + return ErrMismatchValidatorType + } + + index := s.Index(val.Addr()) + + if index == -1 { + return ErrValidatorNotFound + } + + s.Validators = append(s.Validators[:index], s.Validators[index+1:]...) + + return nil +} + +// Merge introduces the given collection into its collection +func (s *Set) Merge(ss Validators) error { + if s.ValidatorType != ss.Type() { + return ErrMismatchValidatorsType + } + + for idx := 0; idx < ss.Len(); idx++ { + newVal := ss.At(uint64(idx)) + + if s.Includes(newVal.Addr()) { + continue + } + + if err := s.Add(newVal); err != nil { + return err + } + } + + return nil +} + +// MarshalRLPWith is a RLP Marshaller +func (s *Set) MarshalRLPWith(arena *fastrlp.Arena) *fastrlp.Value { + vv := arena.NewArray() + + for _, v := range s.Validators { + vv.Set(v.MarshalRLPWith(arena)) + } + + return vv +} + +// UnmarshalRLPFrom is a RLP Unmarshaller +func (s *Set) UnmarshalRLPFrom(p *fastrlp.Parser, val *fastrlp.Value) error { + elems, err := val.GetElems() + if err != nil { + return err + } + + s.Validators = make([]Validator, len(elems)) + + for idx, e := range elems { + if s.Validators[idx], err = NewValidatorFromType(s.ValidatorType); err != nil { + return err + } + + if err := s.Validators[idx].UnmarshalRLPFrom(p, e); err != nil { + return err + } + } + + return nil +} + +// Marshal implements json marshal function +func (s *Set) MarshalJSON() ([]byte, error) { + return json.Marshal(s.Validators) +} + +// UnmarshalJSON implements json unmarshal function +func (s *Set) UnmarshalJSON(data []byte) error { + var ( + rawValidators = []json.RawMessage{} + err error + ) + + if err = json.Unmarshal(data, &rawValidators); err != nil { + return err + } + + validators := make([]Validator, len(rawValidators)) + + for idx := range validators { + if validators[idx], err = NewValidatorFromType(s.ValidatorType); err != nil { + return err + } + + if err := json.Unmarshal(rawValidators[idx], validators[idx]); err != nil { + return err + } + } + + s.Validators = validators + + return nil +} diff --git a/validators/set_test.go b/validators/set_test.go new file mode 100644 index 0000000000..c8b0a0ed0d --- /dev/null +++ b/validators/set_test.go @@ -0,0 +1,617 @@ +package validators + +import ( + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/stretchr/testify/assert" +) + +func TestSetType(t *testing.T) { + t.Parallel() + + t.Run("ECDSAValidators", func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + ECDSAValidatorType, + NewECDSAValidatorSet().Type(), + ) + }) + + t.Run("BLSValidators", func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + BLSValidatorType, + NewBLSValidatorSet().Type(), + ) + }) +} + +func TestSetLen(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + 2, + NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ).Len(), + ) +} + +func TestSetEqual(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + vals1 Validators + vals2 Validators + expected bool + }{ + { + name: "types are not equal", + vals1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + vals2: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + expected: false, + }, + { + name: "sizes are not equal", + vals1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + vals2: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + expected: false, + }, + { + name: "equal (ECDSAValidators)", + vals1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + vals2: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + expected: true, + }, + { + name: "not equal (ECDSAValidators)", + vals1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + vals2: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr1), + ), + expected: false, + }, + { + name: "equal (BLSValidators)", + vals1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + vals2: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + expected: true, + }, + { + name: "not equal (BLSValidators)", + vals1: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + vals2: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr1, testBLSPubKey1), + ), + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.vals1.Equal(test.vals2), + ) + }) + } +} + +func TestSetCopy(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + }{ + { + name: "ECDSAValidators", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + }, + { + name: "BLSValidators", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr1, testBLSPubKey1), + ), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + copied := test.validators.Copy() + + assert.Equal(t, test.validators, copied) + + // check the addresses are different + for i := 0; i < test.validators.Len(); i++ { + assert.NotSame( + t, + test.validators.At(uint64(i)), + copied.At(uint64(i)), + ) + } + }) + } +} + +func TestSetAt(t *testing.T) { + t.Parallel() + + validators := NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ) + + set, ok := validators.(*Set) + assert.True(t, ok) + + for idx, val := range set.Validators { + assert.Equal( + t, + val, + set.At(uint64(idx)), + ) + + // check the addresses are same + assert.Same( + t, + val, + set.At(uint64(idx)), + ) + } +} + +func TestSetIndex(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + addr types.Address + expected int64 + }{ + { + name: "ECDSAValidators", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + addr: addr1, + expected: 0, + }, + { + name: "BLSValidators", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + addr: addr2, + expected: 1, + }, + { + name: "not found", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + addr: types.StringToAddress("fake"), + expected: -1, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.validators.Index(test.addr), + ) + }) + } +} + +func TestSetIncludes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + addr types.Address + expected bool + }{ + { + name: "ECDSAValidators", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + addr: addr1, + expected: true, + }, + { + name: "BLSValidators", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + addr: addr2, + expected: true, + }, + { + name: "not found", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + addr: types.StringToAddress("fake"), + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.validators.Includes(test.addr), + ) + }) + } +} + +func TestSetAdd(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + newValidator Validator + expectedErr error + expectedValidators Validators + }{ + { + name: "should return error in case of type mismatch", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + newValidator: NewBLSValidator(addr2, testBLSPubKey2), + expectedErr: ErrMismatchValidatorType, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + }, + { + name: "should return error in case of duplicated validator", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + newValidator: NewECDSAValidator(addr1), + expectedErr: ErrValidatorAlreadyExists, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + }, + { + name: "should add ECDSA Validator", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + newValidator: NewECDSAValidator(addr2), + expectedErr: nil, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + }, + { + name: "should add BLS Validator", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + ), + newValidator: NewBLSValidator(addr2, testBLSPubKey2), + expectedErr: nil, + expectedValidators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + test.expectedErr, + test.validators.Add(test.newValidator), + ) + + assert.Equal( + t, + test.expectedValidators, + test.validators, + ) + }) + } +} + +func TestSetDel(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + removeValidator Validator + expectedErr error + expectedValidators Validators + }{ + { + name: "should return error in case of type mismatch", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + removeValidator: NewBLSValidator(addr2, testBLSPubKey2), + expectedErr: ErrMismatchValidatorType, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + }, + { + name: "should return error in case of non-existing validator", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + removeValidator: NewECDSAValidator(addr2), + expectedErr: ErrValidatorNotFound, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + }, + { + name: "should remove ECDSA Validator", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + removeValidator: NewECDSAValidator(addr1), + expectedErr: nil, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr2), + ), + }, + { + name: "should remove BLS Validator", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + removeValidator: NewBLSValidator(addr2, testBLSPubKey2), + expectedErr: nil, + expectedValidators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + ), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + test.expectedErr, + test.validators.Del(test.removeValidator), + ) + + assert.Equal( + t, + test.expectedValidators, + test.validators, + ) + }) + } +} + +func TestSetMerge(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators1 Validators + validators2 Validators + expectedErr error + expectedValidators Validators + }{ + { + name: "should return error in case of type mismatch", + validators1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + validators2: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + ), + expectedErr: ErrMismatchValidatorsType, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + }, + { + name: "should merge 2 ECDSAValidators", + validators1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + validators2: NewECDSAValidatorSet( + NewECDSAValidator(addr2), + ), + expectedErr: nil, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + }, + { + name: "should merge BLS Validator", + validators1: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + ), + validators2: NewBLSValidatorSet( + NewBLSValidator(addr2, testBLSPubKey2), + ), + expectedErr: nil, + expectedValidators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + }, + { + name: "should merge 2 ECDSAValidators but ignore the validators that already exists in set1", + validators1: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + ), + validators2: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + expectedErr: nil, + expectedValidators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + test.expectedErr, + test.validators1.Merge(test.validators2), + ) + + assert.Equal( + t, + test.expectedValidators, + test.validators1, + ) + }) + } +} + +func TestSetMarshalAndUnmarshal(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators Validators + }{ + { + name: "ECDSAValidators", + validators: NewECDSAValidatorSet( + NewECDSAValidator(addr1), + NewECDSAValidator(addr2), + ), + }, + { + name: "BLSValidators", + validators: NewBLSValidatorSet( + NewBLSValidator(addr1, testBLSPubKey1), + NewBLSValidator(addr2, testBLSPubKey2), + ), + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + encoded := types.MarshalRLPTo(test.validators.MarshalRLPWith, nil) + + validator2 := &Set{ + ValidatorType: test.validators.Type(), + Validators: []Validator{}, + } + + assert.NoError( + t, + types.UnmarshalRlp(validator2.UnmarshalRLPFrom, encoded), + ) + + assert.Equal( + t, + test.validators, + validator2, + ) + }) + } +} diff --git a/validators/store/contract/contract.go b/validators/store/contract/contract.go new file mode 100644 index 0000000000..dbfa7cfa63 --- /dev/null +++ b/validators/store/contract/contract.go @@ -0,0 +1,127 @@ +package contract + +import ( + "errors" + "fmt" + + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/hashicorp/go-hclog" + lru "github.com/hashicorp/golang-lru" +) + +const ( + // How many validator sets are stored in the cache + // Cache 3 validator sets for 3 epochs + DefaultValidatorSetCacheSize = 3 +) + +var ( + ErrSignerNotFound = errors.New("signer not found") + ErrInvalidValidatorsTypeAssertion = errors.New("invalid type assertion for Validators") +) + +type ContractValidatorStore struct { + logger hclog.Logger + blockchain store.HeaderGetter + executor Executor + + // LRU cache for the validators + validatorSetCache *lru.Cache +} + +type Executor interface { + BeginTxn(types.Hash, *types.Header, types.Address) (*state.Transition, error) +} + +func NewContractValidatorStore( + logger hclog.Logger, + blockchain store.HeaderGetter, + executor Executor, + validatorSetCacheSize int, +) (*ContractValidatorStore, error) { + var ( + validatorsCache *lru.Cache + err error + ) + + if validatorSetCacheSize > 0 { + if validatorsCache, err = lru.New(validatorSetCacheSize); err != nil { + return nil, fmt.Errorf("unable to create validator set cache, %w", err) + } + } + + return &ContractValidatorStore{ + logger: logger, + blockchain: blockchain, + executor: executor, + validatorSetCache: validatorsCache, + }, nil +} + +func (s *ContractValidatorStore) SourceType() store.SourceType { + return store.Contract +} + +func (s *ContractValidatorStore) GetValidatorsByHeight( + validatorType validators.ValidatorType, + height uint64, +) (validators.Validators, error) { + cachedValidators, err := s.loadCachedValidatorSet(height) + if err != nil { + return nil, err + } + + if cachedValidators != nil { + return cachedValidators, nil + } + + transition, err := s.getTransitionForQuery(height) + if err != nil { + return nil, err + } + + fetchedValidators, err := FetchValidators(validatorType, transition, types.ZeroAddress) + if err != nil { + return nil, err + } + + s.saveToValidatorSetCache(height, fetchedValidators) + + return fetchedValidators, nil +} + +func (s *ContractValidatorStore) getTransitionForQuery(height uint64) (*state.Transition, error) { + header, ok := s.blockchain.GetHeaderByNumber(height) + if !ok { + return nil, fmt.Errorf("header not found at %d", height) + } + + return s.executor.BeginTxn(header.StateRoot, header, types.ZeroAddress) +} + +// loadCachedValidatorSet loads validators from validatorSetCache +func (s *ContractValidatorStore) loadCachedValidatorSet(height uint64) (validators.Validators, error) { + cachedRawValidators, ok := s.validatorSetCache.Get(height) + if !ok { + return nil, nil + } + + validators, ok := cachedRawValidators.(validators.Validators) + if !ok { + return nil, ErrInvalidValidatorsTypeAssertion + } + + return validators, nil +} + +// saveToValidatorSetCache saves validators to validatorSetCache +func (s *ContractValidatorStore) saveToValidatorSetCache(height uint64, validators validators.Validators) bool { + if s.validatorSetCache == nil { + return false + } + + return s.validatorSetCache.Add(height, validators) +} diff --git a/validators/store/contract/contract_test.go b/validators/store/contract/contract_test.go new file mode 100644 index 0000000000..96e385f12d --- /dev/null +++ b/validators/store/contract/contract_test.go @@ -0,0 +1,554 @@ +package contract + +import ( + "errors" + "testing" + + "github.com/0xPolygon/polygon-edge/chain" + "github.com/0xPolygon/polygon-edge/contracts/staking" + "github.com/0xPolygon/polygon-edge/crypto" + stakingHelper "github.com/0xPolygon/polygon-edge/helper/staking" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/state" + itrie "github.com/0xPolygon/polygon-edge/state/immutable-trie" + "github.com/0xPolygon/polygon-edge/state/runtime/evm" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/hashicorp/go-hclog" + lru "github.com/hashicorp/golang-lru" + "github.com/stretchr/testify/assert" +) + +var ( + addr1 = types.StringToAddress("1") + addr2 = types.StringToAddress("2") + + testBLSPubKey1 = newTestBLSKeyBytes() + testBLSPubKey2 = newTestBLSKeyBytes() + + testPredeployParams = stakingHelper.PredeployParams{ + MinValidatorCount: 0, + MaxValidatorCount: 10, + } + testBlockGasLimit uint64 = 10000000 +) + +func newTestBLSKeyBytes() validators.BLSValidatorPublicKey { + key, err := crypto.GenerateBLSKey() + if err != nil { + return nil + } + + pubKey, err := key.GetPublicKey() + if err != nil { + return nil + } + + buf, err := pubKey.MarshalBinary() + if err != nil { + return nil + } + + return buf +} + +func newTestCache(t *testing.T, size int) *lru.Cache { + t.Helper() + + cache, err := lru.New(size) + assert.NoError(t, err) + + return cache +} + +type mockExecutor struct { + BeginTxnFn func(types.Hash, *types.Header, types.Address) (*state.Transition, error) +} + +func (m *mockExecutor) BeginTxn( + hash types.Hash, + header *types.Header, + address types.Address, +) (*state.Transition, error) { + return m.BeginTxnFn(hash, header, address) +} + +func newTestTransition( + t *testing.T, +) *state.Transition { + t.Helper() + + st := itrie.NewState(itrie.NewMemoryStorage()) + + ex := state.NewExecutor(&chain.Params{ + Forks: chain.AllForksEnabled, + }, st, hclog.NewNullLogger()) + + rootHash := ex.WriteGenesis(nil) + + ex.SetRuntime(evm.NewEVM()) + ex.GetHash = func(h *types.Header) state.GetHashByNumber { + return func(i uint64) types.Hash { + return rootHash + } + } + + transition, err := ex.BeginTxn( + rootHash, + &types.Header{ + // Set enough block gas limit for query + GasLimit: testBlockGasLimit, + }, + types.ZeroAddress, + ) + assert.NoError(t, err) + + return transition +} + +func newTestTransitionWithPredeployedStakingContract( + t *testing.T, + validators validators.Validators, +) *state.Transition { + t.Helper() + + transition := newTestTransition(t) + + contractState, err := stakingHelper.PredeployStakingSC( + validators, + testPredeployParams, + ) + + assert.NoError(t, err) + + assert.NoError( + t, + transition.SetAccountDirectly(staking.AddrStakingContract, contractState), + ) + + return transition +} + +func newTestContractValidatorStore( + t *testing.T, + blockchain store.HeaderGetter, + executor Executor, + cacheSize int, +) *ContractValidatorStore { + t.Helper() + + var cache *lru.Cache + if cacheSize > 0 { + cache = newTestCache(t, cacheSize) + } + + return &ContractValidatorStore{ + logger: hclog.NewNullLogger(), + blockchain: blockchain, + executor: executor, + validatorSetCache: cache, + } +} + +func TestNewContractValidatorStore(t *testing.T) { + t.Parallel() + + var ( + logger = hclog.NewNullLogger() + blockchain = store.HeaderGetter( + &store.MockBlockchain{}, + ) + executor = Executor( + &mockExecutor{}, + ) + ) + + tests := []struct { + name string + cacheSize int + expectedRes *ContractValidatorStore + expectedErr error + }{ + { + name: "should return store", + cacheSize: 1, + expectedRes: &ContractValidatorStore{ + logger: logger, + blockchain: blockchain, + executor: executor, + validatorSetCache: newTestCache(t, 1), + }, + expectedErr: nil, + }, + { + name: "should return store without cache if cache size is zero", + cacheSize: 0, + expectedRes: &ContractValidatorStore{ + logger: logger, + blockchain: blockchain, + executor: executor, + }, + expectedErr: nil, + }, + { + name: "should return store without cache if cache size is negative", + cacheSize: -1, + expectedRes: &ContractValidatorStore{ + logger: logger, + blockchain: blockchain, + executor: executor, + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := NewContractValidatorStore( + logger, + blockchain, + executor, + test.cacheSize, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} + +func TestContractValidatorStoreSourceType(t *testing.T) { + t.Parallel() + + s := &ContractValidatorStore{} + + assert.Equal(t, store.Contract, s.SourceType()) +} + +func TestContractValidatorStoreGetValidators(t *testing.T) { + t.Parallel() + + var ( + stateRoot = types.StringToHash("1") + header = &types.Header{ + StateRoot: stateRoot, + } + + ecdsaValidators = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + validators.NewECDSAValidator(addr2), + ) + + blsValidators = validators.NewBLSValidatorSet( + validators.NewBLSValidator(addr1, testBLSPubKey1), + validators.NewBLSValidator(addr2, testBLSPubKey2), + ) + + transitionForECDSAValidators = newTestTransitionWithPredeployedStakingContract( + t, + ecdsaValidators, + ) + + transitionForBLSValidators = newTestTransitionWithPredeployedStakingContract( + t, + blsValidators, + ) + ) + + tests := []struct { + name string + blockchain store.HeaderGetter + executor Executor + cacheSize int + initialCaches map[uint64]interface{} + + // input + validatorType validators.ValidatorType + height uint64 + + // output + expectedRes validators.Validators + expectedErr error + // caches after calling GetValidators + finalCaches map[uint64]interface{} + }{ + { + name: "should return error when loadCachedValidatorSet failed", + blockchain: nil, + executor: nil, + cacheSize: 1, + initialCaches: map[uint64]interface{}{ + 0: string("fake"), + }, + height: 0, + expectedRes: nil, + expectedErr: ErrInvalidValidatorsTypeAssertion, + finalCaches: map[uint64]interface{}{ + 0: string("fake"), + }, + }, + { + name: "should return validators if cache exists", + blockchain: nil, + executor: nil, + cacheSize: 1, + initialCaches: map[uint64]interface{}{ + 0: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + ), + }, + height: 0, + expectedRes: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + ), + expectedErr: nil, + finalCaches: map[uint64]interface{}{ + 0: validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + ), + }, + }, + { + name: "should return error if header not found", + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, uint64(1), height) + + return nil, false + }, + }, + executor: nil, + cacheSize: 1, + initialCaches: map[uint64]interface{}{}, + height: 1, + expectedRes: nil, + expectedErr: errors.New("header not found at 1"), + finalCaches: map[uint64]interface{}{}, + }, + { + name: "should return error if FetchValidators failed", + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, uint64(1), height) + + return header, true + }, + }, + executor: &mockExecutor{ + BeginTxnFn: func(hash types.Hash, head *types.Header, addr types.Address) (*state.Transition, error) { + assert.Equal(t, stateRoot, hash) + assert.Equal(t, header, head) + assert.Equal(t, types.ZeroAddress, addr) + + return transitionForECDSAValidators, nil + }, + }, + cacheSize: 1, + initialCaches: map[uint64]interface{}{}, + validatorType: validators.ValidatorType("fake"), + height: 1, + expectedRes: nil, + expectedErr: errors.New("unsupported validator type: fake"), + finalCaches: map[uint64]interface{}{}, + }, + { + name: "should return fetched ECDSA validators", + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, uint64(1), height) + + return header, true + }, + }, + executor: &mockExecutor{ + BeginTxnFn: func(hash types.Hash, head *types.Header, addr types.Address) (*state.Transition, error) { + assert.Equal(t, stateRoot, hash) + assert.Equal(t, header, head) + assert.Equal(t, types.ZeroAddress, addr) + + return transitionForECDSAValidators, nil + }, + }, + cacheSize: 1, + initialCaches: map[uint64]interface{}{}, + validatorType: validators.ECDSAValidatorType, + height: 1, + expectedRes: ecdsaValidators, + expectedErr: nil, + finalCaches: map[uint64]interface{}{ + 1: ecdsaValidators, + }, + }, + { + name: "should return fetched BLS validators", + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, uint64(1), height) + + return header, true + }, + }, + executor: &mockExecutor{ + BeginTxnFn: func(hash types.Hash, head *types.Header, addr types.Address) (*state.Transition, error) { + assert.Equal(t, stateRoot, hash) + assert.Equal(t, header, head) + assert.Equal(t, types.ZeroAddress, addr) + + return transitionForBLSValidators, nil + }, + }, + cacheSize: 1, + initialCaches: map[uint64]interface{}{}, + validatorType: validators.BLSValidatorType, + height: 1, + expectedRes: blsValidators, + expectedErr: nil, + finalCaches: map[uint64]interface{}{ + 1: blsValidators, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + store := newTestContractValidatorStore( + t, + test.blockchain, + test.executor, + test.cacheSize, + ) + + for height, data := range test.initialCaches { + store.validatorSetCache.Add(height, data) + } + + res, err := store.GetValidatorsByHeight(test.validatorType, test.height) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + + // check cache + assert.Equal(t, len(test.finalCaches), store.validatorSetCache.Len()) + + for height, expected := range test.finalCaches { + cache, ok := store.validatorSetCache.Get(height) + + assert.True(t, ok) + assert.Equal(t, expected, cache) + } + }) + } +} + +func TestContractValidatorStore_CacheChange(t *testing.T) { + t.Parallel() + + var ( + cacheSize = 2 + + store = newTestContractValidatorStore( + t, + nil, + nil, + cacheSize, + ) + + ecdsaValidators1 = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + ) + + ecdsaValidators2 = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + validators.NewECDSAValidator(addr2), + ) + + blsValidators = validators.NewBLSValidatorSet( + validators.NewBLSValidator(addr1, testBLSPubKey1), + validators.NewBLSValidator(addr2, testBLSPubKey2), + ) + ) + + testCache := func(t *testing.T, expectedCache map[uint64]validators.Validators) { + t.Helper() + + assert.Equal(t, len(expectedCache), store.validatorSetCache.Len()) + + for height, expected := range expectedCache { + cache, ok := store.validatorSetCache.Get(height) + + assert.Truef(t, ok, "validators for %d must exist, but not found") + assert.Equal(t, expected, cache) + } + } + + // initial cache is empty + testCache(t, nil) + + // overflow doesn't occur + assert.False( + t, + store.saveToValidatorSetCache(0, ecdsaValidators1), + ) + + testCache(t, map[uint64]validators.Validators{ + 0: ecdsaValidators1, + }) + + assert.False( + t, + store.saveToValidatorSetCache(1, ecdsaValidators2), + ) + + testCache(t, map[uint64]validators.Validators{ + 0: ecdsaValidators1, + 1: ecdsaValidators2, + }) + + // make sure ecdsaValidators2 is loaded at the end for LRU cache + store.validatorSetCache.Get(1) + + // overflow occurs and one validator set is removed + assert.True( + t, + store.saveToValidatorSetCache(2, blsValidators), + ) + + testCache(t, map[uint64]validators.Validators{ + 1: ecdsaValidators2, + 2: blsValidators, + }) +} + +func TestContractValidatorStore_NoCache(t *testing.T) { + t.Parallel() + + var ( + store = newTestContractValidatorStore( + t, + nil, + nil, + 0, + ) + + ecdsaValidators1 = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + ) + ) + + // nothing happens because cache is nil + assert.False( + t, + store.saveToValidatorSetCache(0, ecdsaValidators1), + ) + + assert.Nil(t, store.validatorSetCache) +} diff --git a/validators/store/contract/fetcher.go b/validators/store/contract/fetcher.go new file mode 100644 index 0000000000..2582cc5a2a --- /dev/null +++ b/validators/store/contract/fetcher.go @@ -0,0 +1,83 @@ +package contract + +import ( + "fmt" + + "github.com/0xPolygon/polygon-edge/contracts/staking" + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +// FetchValidators fetches validators from a contract switched by validator type +func FetchValidators( + validatorType validators.ValidatorType, + transition *state.Transition, + from types.Address, +) (validators.Validators, error) { + switch validatorType { + case validators.ECDSAValidatorType: + return FetchECDSAValidators(transition, from) + case validators.BLSValidatorType: + return FetchBLSValidators(transition, from) + } + + return nil, fmt.Errorf("unsupported validator type: %s", validatorType) +} + +// FetchECDSAValidators queries a contract for validator addresses and returns ECDSAValidators +func FetchECDSAValidators( + transition *state.Transition, + from types.Address, +) (validators.Validators, error) { + valAddrs, err := staking.QueryValidators(transition, from) + if err != nil { + return nil, err + } + + ecdsaValidators := validators.NewECDSAValidatorSet() + for _, addr := range valAddrs { + if err := ecdsaValidators.Add(validators.NewECDSAValidator(addr)); err != nil { + return nil, err + } + } + + return ecdsaValidators, nil +} + +// FetchBLSValidators queries a contract for validator addresses & BLS Public Keys and returns ECDSAValidators +func FetchBLSValidators( + transition *state.Transition, + from types.Address, +) (validators.Validators, error) { + valAddrs, err := staking.QueryValidators(transition, from) + if err != nil { + return nil, err + } + + blsPublicKeys, err := staking.QueryBLSPublicKeys(transition, from) + if err != nil { + return nil, err + } + + blsValidators := validators.NewBLSValidatorSet() + + for idx := range valAddrs { + // ignore the validator whose BLS Key is not set + // because BLS validator needs to have both Address and BLS Public Key set + // in the contract + if _, err := crypto.UnmarshalBLSPublicKey(blsPublicKeys[idx]); err != nil { + continue + } + + if err := blsValidators.Add(validators.NewBLSValidator( + valAddrs[idx], + blsPublicKeys[idx], + )); err != nil { + return nil, err + } + } + + return blsValidators, nil +} diff --git a/validators/store/contract/fetcher_test.go b/validators/store/contract/fetcher_test.go new file mode 100644 index 0000000000..97e4524065 --- /dev/null +++ b/validators/store/contract/fetcher_test.go @@ -0,0 +1,142 @@ +package contract + +import ( + "errors" + "fmt" + "testing" + + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/state" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +func TestFetchValidators(t *testing.T) { + t.Parallel() + + // only check error handling because of the duplicated tests below + fakeValidatorType := validators.ValidatorType("fake") + res, err := FetchValidators( + fakeValidatorType, + nil, + types.ZeroAddress, + ) + + assert.Nil(t, res) + assert.ErrorContains(t, err, fmt.Sprintf("unsupported validator type: %s", fakeValidatorType)) +} + +func TestFetchECDSAValidators(t *testing.T) { + t.Parallel() + + var ( + ecdsaValidators = validators.NewECDSAValidatorSet( + validators.NewECDSAValidator(addr1), + validators.NewECDSAValidator(addr2), + ) + ) + + tests := []struct { + name string + transition *state.Transition + from types.Address + expectedRes validators.Validators + expectedErr error + }{ + { + name: "should return error if QueryValidators failed", + transition: newTestTransition( + t, + ), + from: types.ZeroAddress, + expectedRes: nil, + expectedErr: errors.New("empty input"), + }, + { + name: "should return ECDSA Validators", + transition: newTestTransitionWithPredeployedStakingContract( + t, + ecdsaValidators, + ), + from: types.ZeroAddress, + expectedRes: ecdsaValidators, + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := FetchValidators( + validators.ECDSAValidatorType, + test.transition, + test.from, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} + +func TestFetchBLSValidators(t *testing.T) { + t.Parallel() + + var ( + blsValidators = validators.NewBLSValidatorSet( + validators.NewBLSValidator(addr1, testBLSPubKey1), + validators.NewBLSValidator(addr2, []byte{}), // validator 2 has not set BLS Public Key + ) + ) + + tests := []struct { + name string + transition *state.Transition + from types.Address + expectedRes validators.Validators + expectedErr error + }{ + { + name: "should return error if QueryValidators failed", + transition: newTestTransition( + t, + ), + from: types.ZeroAddress, + expectedRes: nil, + expectedErr: errors.New("empty input"), + }, + { + name: "should return ECDSA Validators", + transition: newTestTransitionWithPredeployedStakingContract( + t, + blsValidators, + ), + from: types.ZeroAddress, + expectedRes: validators.NewBLSValidatorSet( + validators.NewBLSValidator(addr1, testBLSPubKey1), + ), + expectedErr: nil, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := FetchValidators( + validators.BLSValidatorType, + test.transition, + test.from, + ) + + assert.Equal(t, test.expectedRes, res) + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + }) + } +} diff --git a/validators/store/snapshot/helper.go b/validators/store/snapshot/helper.go new file mode 100644 index 0000000000..ce2bda7d82 --- /dev/null +++ b/validators/store/snapshot/helper.go @@ -0,0 +1,47 @@ +package snapshot + +import ( + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +// isAuthorize is a helper function to return the bool value from Nonce +func isAuthorize( + nonce types.Nonce, +) (bool, error) { + switch nonce { + case nonceAuthVote: + return true, nil + case nonceDropVote: + return false, nil + default: + return false, ErrIncorrectNonce + } +} + +// shouldProcessVote is a helper function to return +// the flag indicating whether vote should be processed or not +// based on vote action and validator set +func shouldProcessVote( + validators validators.Validators, + candidate types.Address, + voteAction bool, // true => add, false => remove +) bool { + // if vote action is... + // true => validator set expects not to have a candidate + // false => validator set expects to have a candidate + return voteAction != validators.Includes(candidate) +} + +// addsOrDelsCandidate is a helper function to add/remove candidate to/from validators +func addsOrDelsCandidate( + validators validators.Validators, + candidate validators.Validator, + updateAction bool, +) error { + if updateAction { + return validators.Add(candidate) + } else { + return validators.Del(candidate) + } +} diff --git a/validators/store/snapshot/helper_test.go b/validators/store/snapshot/helper_test.go new file mode 100644 index 0000000000..5a7b80c6df --- /dev/null +++ b/validators/store/snapshot/helper_test.go @@ -0,0 +1,306 @@ +package snapshot + +import ( + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +var ( + addr1 = types.StringToAddress("1") + addr2 = types.StringToAddress("2") + addr3 = types.StringToAddress("3") + testBLSPubKey1 = validators.BLSValidatorPublicKey([]byte("bls_pubkey1")) + testBLSPubKey2 = validators.BLSValidatorPublicKey([]byte("bls_pubkey2")) + testBLSPubKey3 = validators.BLSValidatorPublicKey([]byte("bls_pubkey3")) + + ecdsaValidator1 = validators.NewECDSAValidator(addr1) + ecdsaValidator2 = validators.NewECDSAValidator(addr2) + ecdsaValidator3 = validators.NewECDSAValidator(addr3) + blsValidator1 = validators.NewBLSValidator(addr1, testBLSPubKey1) + blsValidator2 = validators.NewBLSValidator(addr2, testBLSPubKey2) + blsValidator3 = validators.NewBLSValidator(addr3, testBLSPubKey3) +) + +func Test_isAuthorize(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + nonce types.Nonce + expectedFlag bool + expectedErr error + }{ + { + name: "nonceAuthVote", + nonce: nonceAuthVote, + expectedFlag: true, + expectedErr: nil, + }, + { + name: "nonceDropVote", + nonce: nonceDropVote, + expectedFlag: false, + expectedErr: nil, + }, + { + name: "invalid nonce", + nonce: types.Nonce{0x1}, + expectedFlag: false, + expectedErr: ErrIncorrectNonce, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := isAuthorize(test.nonce) + + assert.Equal(t, test.expectedFlag, res) + assert.ErrorIs(t, test.expectedErr, err) + }) + } +} + +func Test_shouldProcessVote(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validators validators.Validators + candidate types.Address + voteAction bool + expected bool + }{ + // ECDSA + { + name: "ECDSA: vote for addition when the candidate isn't in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + candidate: ecdsaValidator2.Addr(), + voteAction: true, + expected: true, + }, + { + name: "ECDSA: vote for addition when the candidate is already in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + candidate: ecdsaValidator2.Addr(), + voteAction: true, + expected: false, + }, + { + name: "ECDSA: vote for deletion when the candidate is in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + candidate: ecdsaValidator2.Addr(), + voteAction: false, + expected: true, + }, + { + name: "ECDSA: vote for deletion when the candidate isn't in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + candidate: ecdsaValidator2.Addr(), + voteAction: false, + expected: false, + }, + // BLS + { + name: "BLS: vote for addition when the candidate isn't in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + candidate: blsValidator2.Addr(), + voteAction: true, + expected: true, + }, + { + name: "BLS: vote for addition when the candidate is already in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + candidate: blsValidator2.Addr(), + voteAction: true, + expected: false, + }, + { + name: "BLS: vote for deletion when the candidate is in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + candidate: blsValidator1.Addr(), + voteAction: false, + expected: true, + }, + { + name: "BLS: vote for deletion when the candidate isn't in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + candidate: blsValidator2.Addr(), + voteAction: false, + expected: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + shouldProcessVote(test.validators, test.candidate, test.voteAction), + ) + }) + } +} + +func Test_addsOrDelsCandidate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + // inputs + validators validators.Validators + candidate validators.Validator + updateAction bool + // outputs + expectedErr error + newValidators validators.Validators + }{ + // ECDSA + { + name: "ECDSA: addition when the candidate isn't in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + candidate: ecdsaValidator2, + updateAction: true, + expectedErr: nil, + newValidators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + { + name: "ECDSA: addition when the candidate is already in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + candidate: ecdsaValidator2, + updateAction: true, + expectedErr: validators.ErrValidatorAlreadyExists, + newValidators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + { + name: "ECDSA: deletion when the candidate is in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + candidate: ecdsaValidator1, + updateAction: false, + expectedErr: nil, + newValidators: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + }, + { + name: "ECDSA: deletion when the candidate isn't in validators", + validators: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + candidate: ecdsaValidator1, + updateAction: false, + expectedErr: validators.ErrValidatorNotFound, + newValidators: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + }, + // BLS + { + name: "BLS: addition when the candidate isn't in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + ), + candidate: blsValidator2, + updateAction: true, + expectedErr: nil, + newValidators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + }, + { + name: "BLS: addition when the candidate is already in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + candidate: blsValidator2, + updateAction: true, + expectedErr: validators.ErrValidatorAlreadyExists, + newValidators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + }, + { + name: "BLS: deletion when the candidate is in validators", + validators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + candidate: blsValidator1, + updateAction: false, + expectedErr: nil, + newValidators: validators.NewBLSValidatorSet( + blsValidator2, + ), + }, + { + name: "BLS: deletion when the candidate is in validators", + validators: validators.NewBLSValidatorSet( + blsValidator2, + ), + candidate: blsValidator1, + updateAction: false, + expectedErr: validators.ErrValidatorNotFound, + newValidators: validators.NewBLSValidatorSet( + blsValidator2, + ), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + err := addsOrDelsCandidate( + test.validators, + test.candidate, + test.updateAction, + ) + + assert.ErrorIs(t, test.expectedErr, err) + assert.Equal(t, test.newValidators, test.validators) + }) + } +} diff --git a/validators/store/snapshot/snapshot.go b/validators/store/snapshot/snapshot.go new file mode 100644 index 0000000000..c1c738eadd --- /dev/null +++ b/validators/store/snapshot/snapshot.go @@ -0,0 +1,627 @@ +package snapshot + +import ( + "bytes" + "errors" + "fmt" + "sync" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/hashicorp/go-hclog" +) + +const ( + loggerName = "snapshot_validator_set" +) + +// SignerInterface is an interface of the Signer SnapshotValidatorStore calls +type SignerInterface interface { + Type() validators.ValidatorType + EcrecoverFromHeader(*types.Header) (types.Address, error) + GetValidators(*types.Header) (validators.Validators, error) +} + +var ( + // Magic nonce number to vote on adding a new validator + nonceAuthVote = types.Nonce{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + + // Magic nonce number to vote on removing a validator. + nonceDropVote = types.Nonce{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +) + +var ( + ErrInvalidNonce = errors.New("invalid nonce specified") + ErrSnapshotNotFound = errors.New("not found snapshot") + ErrUnauthorizedProposer = errors.New("unauthorized proposer") + ErrIncorrectNonce = errors.New("incorrect vote nonce") + ErrAlreadyCandidate = errors.New("already a candidate") + ErrCandidateIsValidator = errors.New("the candidate is already a validator") + ErrCandidateNotExistInSet = errors.New("cannot remove a validator if they're not in the snapshot") + ErrAlreadyVoted = errors.New("already voted for this address") + ErrMultipleVotesBySameValidator = errors.New("more than one proposal per validator per address found") +) + +type SnapshotValidatorStore struct { + // interface + logger hclog.Logger + blockchain store.HeaderGetter + getSigner func(uint64) (SignerInterface, error) + + // configuration + epochSize uint64 + + // data + store *snapshotStore + candidates []*store.Candidate + candidatesLock sync.RWMutex +} + +// NewSnapshotValidatorStore creates and initializes *SnapshotValidatorStore +func NewSnapshotValidatorStore( + logger hclog.Logger, + blockchain store.HeaderGetter, + getSigner func(uint64) (SignerInterface, error), + epochSize uint64, + metadata *SnapshotMetadata, + snapshots []*Snapshot, +) (*SnapshotValidatorStore, error) { + set := &SnapshotValidatorStore{ + logger: logger.Named(loggerName), + store: newSnapshotStore(metadata, snapshots), + blockchain: blockchain, + getSigner: getSigner, + candidates: make([]*store.Candidate, 0), + candidatesLock: sync.RWMutex{}, + epochSize: epochSize, + } + + if err := set.initialize(); err != nil { + return nil, err + } + + return set, nil +} + +// initialize setup the snapshots to catch up latest header in blockchain +func (s *SnapshotValidatorStore) initialize() error { + header := s.blockchain.Header() + meta := s.GetSnapshotMetadata() + + if header.Number == 0 { + // Genesis header needs to be set by hand, all the other + // snapshots are set as part of processHeaders + if err := s.addHeaderSnap(header); err != nil { + return err + } + } + + // If the snapshot is not found, or the latest snapshot belongs to a previous epoch, + // we need to start rebuilding the snapshot from the beginning of the current epoch + // in order to have all the votes and validators correctly set in the snapshot, + // since they reset every epoch. + + // Get epoch of latest header and saved metadata + var ( + currentEpoch = header.Number / s.epochSize + metaEpoch = meta.LastBlock / s.epochSize + + snapshot = s.getSnapshot(header.Number) + ) + + if snapshot == nil || metaEpoch < currentEpoch { + // Restore snapshot at the beginning of the current epoch by block header + // if list doesn't have any snapshots to calculate snapshot for the next header + s.logger.Info("snapshot was not found, restore snapshot at beginning of current epoch", "current epoch", currentEpoch) + beginHeight := currentEpoch * s.epochSize + + beginHeader, ok := s.blockchain.GetHeaderByNumber(beginHeight) + if !ok { + return fmt.Errorf("header at %d not found", beginHeight) + } + + if err := s.addHeaderSnap(beginHeader); err != nil { + return err + } + + s.store.updateLastBlock(beginHeight) + + meta = s.GetSnapshotMetadata() + } + + // Process headers if we missed some blocks in the current epoch + if header.Number > meta.LastBlock { + s.logger.Info("syncing past snapshots", "from", meta.LastBlock, "to", header.Number) + + if err := s.ProcessHeadersInRange(meta.LastBlock+1, header.Number); err != nil { + return err + } + } + + return nil +} + +// SourceType returns validator store type +func (s *SnapshotValidatorStore) SourceType() store.SourceType { + return store.Snapshot +} + +// GetSnapshotMetadata returns metadata +func (s *SnapshotValidatorStore) GetSnapshotMetadata() *SnapshotMetadata { + return &SnapshotMetadata{ + LastBlock: s.store.getLastBlock(), + } +} + +// GetSnapshots returns all Snapshots +func (s *SnapshotValidatorStore) GetSnapshots() []*Snapshot { + return s.store.list +} + +// Candidates returns the current candidates +func (s *SnapshotValidatorStore) Candidates() []*store.Candidate { + return s.candidates +} + +// GetValidators returns the validator set in the Snapshot for the given height +func (s *SnapshotValidatorStore) GetValidatorsByHeight(height uint64) (validators.Validators, error) { + snapshot := s.getSnapshot(height) + if snapshot == nil { + return nil, ErrSnapshotNotFound + } + + return snapshot.Set, nil +} + +// Votes returns the votes in the snapshot at the specified height +func (s *SnapshotValidatorStore) Votes(height uint64) ([]*store.Vote, error) { + snapshot := s.getSnapshot(height) + if snapshot == nil { + return nil, ErrSnapshotNotFound + } + + return snapshot.Votes, nil +} + +// UpdateValidatorSet resets Snapshot with given validators at specified height +func (s *SnapshotValidatorStore) UpdateValidatorSet( + // new validators to be overwritten + newValidators validators.Validators, + // the height from which new validators are used + fromHeight uint64, +) error { + snapshotHeight := fromHeight - 1 + + header, ok := s.blockchain.GetHeaderByNumber(snapshotHeight) + if !ok { + return fmt.Errorf("header at %d not found", snapshotHeight) + } + + s.store.putByNumber(&Snapshot{ + Number: header.Number, + Hash: header.Hash.String(), + // reset validators & votes + Set: newValidators, + Votes: []*store.Vote{}, + }) + + return nil +} + +// ModifyHeader updates Header to vote +func (s *SnapshotValidatorStore) ModifyHeader(header *types.Header, proposer types.Address) error { + snapshot := s.getSnapshot(header.Number) + if snapshot == nil { + return ErrSnapshotNotFound + } + + if candidate := s.getNextCandidate(snapshot, proposer); candidate != nil { + var err error + + header.Miner, err = validatorToMiner(candidate.Validator) + if err != nil { + return err + } + + if candidate.Authorize { + header.Nonce = nonceAuthVote + } else { + header.Nonce = nonceDropVote + } + } + + return nil +} + +// VerifyHeader verifies the fields of Header which are modified in ModifyHeader +func (s *SnapshotValidatorStore) VerifyHeader(header *types.Header) error { + // Check the nonce format. + // The nonce field must have either an AUTH or DROP vote value. + // Block nonce values are not taken into account when the Miner field is set to zeroes, indicating + // no vote casting is taking place within a block + if header.Nonce != nonceAuthVote && header.Nonce != nonceDropVote { + return ErrInvalidNonce + } + + return nil +} + +// ProcessHeadersInRange is a helper function process headers in the given range +func (s *SnapshotValidatorStore) ProcessHeadersInRange( + from, to uint64, +) error { + for i := from; i <= to; i++ { + if i == 0 { + continue + } + + header, ok := s.blockchain.GetHeaderByNumber(i) + if !ok { + return fmt.Errorf("header %d not found", i) + } + + if err := s.ProcessHeader(header); err != nil { + return err + } + } + + return nil +} + +// ProcessHeader processes the header and updates snapshots +func (s *SnapshotValidatorStore) ProcessHeader( + header *types.Header, +) error { + signer, err := s.getSigner(header.Number) + if err != nil { + return err + } + + if signer == nil { + return fmt.Errorf("signer not found at %d", header.Number) + } + + proposer, err := signer.EcrecoverFromHeader(header) + if err != nil { + return err + } + + parentSnap := s.getSnapshot(header.Number - 1) + if parentSnap == nil { + return ErrSnapshotNotFound + } + + if !parentSnap.Set.Includes(proposer) { + return ErrUnauthorizedProposer + } + + snap := parentSnap.Copy() + + // Reset votes when new epoch + if header.Number%s.epochSize == 0 { + s.resetSnapshot(parentSnap, snap, header) + s.removeLowerSnapshots(header.Number) + s.store.updateLastBlock(header.Number) + + return nil + } + + // no vote if miner field is not set + if bytes.Equal(header.Miner, types.ZeroAddress[:]) { + s.store.updateLastBlock(header.Number) + + return nil + } + + // Process votes in the middle of epoch + if err := processVote(snap, header, signer.Type(), proposer); err != nil { + return err + } + + s.store.updateLastBlock(header.Number) + s.saveSnapshotIfChanged(parentSnap, snap, header) + + return nil +} + +// Propose adds new candidate for vote +func (s *SnapshotValidatorStore) Propose(candidate validators.Validator, auth bool, proposer types.Address) error { + s.candidatesLock.Lock() + defer s.candidatesLock.Unlock() + + candidateAddr := candidate.Addr() + + for _, c := range s.candidates { + if c.Validator.Addr() == candidateAddr { + return ErrAlreadyCandidate + } + } + + snap := s.getLatestSnapshot() + if snap == nil { + return ErrSnapshotNotFound + } + + included := snap.Set.Includes(candidateAddr) + + // safe checks + if auth && included { + return ErrCandidateIsValidator + } else if !auth && !included { + return ErrCandidateNotExistInSet + } + + // check if we have already voted for this candidate + count := snap.CountByVoterAndCandidate(proposer, candidate) + if count == 1 { + return ErrAlreadyVoted + } + + return s.addCandidate( + snap.Set, + candidate, + auth, + ) +} + +// AddCandidate adds new candidate to candidate list +// unsafe against concurrent access +func (s *SnapshotValidatorStore) addCandidate( + validators validators.Validators, + candidate validators.Validator, + authrorize bool, +) error { + if authrorize { + s.candidates = append(s.candidates, &store.Candidate{ + Validator: candidate, + Authorize: authrorize, + }) + + return nil + } + + // Get candidate validator information from set + // because don't want user to specify data except for address + // in case of removal + validatorIndex := validators.Index(candidate.Addr()) + if validatorIndex == -1 { + return ErrCandidateNotExistInSet + } + + s.candidates = append(s.candidates, &store.Candidate{ + Validator: validators.At(uint64(validatorIndex)), + Authorize: authrorize, + }) + + return nil +} + +// addHeaderSnap creates the initial snapshot, and adds it to the snapshot store +func (s *SnapshotValidatorStore) addHeaderSnap(header *types.Header) error { + signer, err := s.getSigner(header.Number) + if err != nil { + return err + } + + if signer == nil { + return fmt.Errorf("signer not found %d", header.Number) + } + + validators, err := signer.GetValidators(header) + if err != nil { + return err + } + + // Create the first snapshot from the genesis + s.store.add(&Snapshot{ + Hash: header.Hash.String(), + Number: header.Number, + Votes: []*store.Vote{}, + Set: validators, + }) + + return nil +} + +// getSnapshot returns a snapshot for specified height +func (s *SnapshotValidatorStore) getSnapshot(height uint64) *Snapshot { + return s.store.find(height) +} + +// getLatestSnapshot returns a snapshot for latest height +func (s *SnapshotValidatorStore) getLatestSnapshot() *Snapshot { + return s.getSnapshot(s.store.lastNumber) +} + +// getNextCandidate returns a possible candidate from candidates list +func (s *SnapshotValidatorStore) getNextCandidate( + snap *Snapshot, + proposer types.Address, +) *store.Candidate { + s.candidatesLock.Lock() + defer s.candidatesLock.Unlock() + + // first, we need to remove any candidates that have already been + // selected as validators + s.cleanObsoleteCandidates(snap.Set) + + // now pick the first candidate that has not received a vote yet + return s.pickOneCandidate(snap, proposer) +} + +// cleanObsolateCandidates removes useless candidates from candidates field +// Unsafe against concurrent accesses +func (s *SnapshotValidatorStore) cleanObsoleteCandidates(set validators.Validators) { + newCandidates := make([]*store.Candidate, 0, len(s.candidates)) + + for _, candidate := range s.candidates { + // If Authorize is + // true => Candidate needs to be in Set + // false => Candidate needs not to be in Set + // if the current situetion is not so, it's still a candidate + if candidate.Authorize != set.Includes(candidate.Validator.Addr()) { + newCandidates = append(newCandidates, candidate) + } + } + + s.candidates = newCandidates +} + +// pickOneCandidate returns a proposer candidate from candidates field +// Unsafe against concurrent accesses +func (s *SnapshotValidatorStore) pickOneCandidate( + snap *Snapshot, + proposer types.Address, +) *store.Candidate { + for _, c := range s.candidates { + addr := c.Validator.Addr() + + count := snap.Count(func(v *store.Vote) bool { + return v.Candidate.Addr() == addr && v.Validator == proposer + }) + + if count == 0 { + return c + } + } + + return nil +} + +// saveSnapshotIfChanged is a helper method to save snapshot updated by the given header +// only if the snapshot is updated from parent snapshot +func (s *SnapshotValidatorStore) saveSnapshotIfChanged( + parentSnapshot, snapshot *Snapshot, + header *types.Header, +) { + if snapshot.Equal(parentSnapshot) { + return + } + + snapshot.Number = header.Number + snapshot.Hash = header.Hash.String() + + s.store.add(snapshot) +} + +// resetSnapshot is a helper method to save a snapshot that clears votes +func (s *SnapshotValidatorStore) resetSnapshot( + parentSnapshot, snapshot *Snapshot, + header *types.Header, +) { + snapshot.Votes = nil + + s.saveSnapshotIfChanged(parentSnapshot, snapshot, header) +} + +// removeLowerSnapshots is a helper function to removes old snapshots +func (s *SnapshotValidatorStore) removeLowerSnapshots( + currentHeight uint64, +) { + // remove in-memory snapshots from two epochs before this one + lowerEpoch := int(currentHeight/s.epochSize) - 2 + if lowerEpoch > 0 { + purgeBlock := uint64(lowerEpoch) * s.epochSize + s.store.deleteLower(purgeBlock) + } +} + +// processVote processes vote in the given header and update snapshot +func processVote( + snapshot *Snapshot, + header *types.Header, + candidateType validators.ValidatorType, + proposer types.Address, +) error { + // the nonce selects the action + authorize, err := isAuthorize(header.Nonce) + if err != nil { + return err + } + + // parse candidate validator set from header.Miner + candidate, err := minerToValidator(candidateType, header.Miner) + if err != nil { + return err + } + + // if candidate has been processed as expected, just update last block + if !shouldProcessVote(snapshot.Set, candidate.Addr(), authorize) { + return nil + } + + voteCount := snapshot.CountByVoterAndCandidate(proposer, candidate) + if voteCount > 1 { + // there can only be one vote per validator per address + return ErrMultipleVotesBySameValidator + } + + if voteCount == 0 { + // cast the new vote since there is no one yet + snapshot.AddVote(proposer, candidate, authorize) + } + + // check the tally for the proposed validator + totalVotes := snapshot.CountByCandidate(candidate) + + // If more than a half of all validators voted + if totalVotes > snapshot.Set.Len()/2 { + if err := addsOrDelsCandidate( + snapshot.Set, + candidate, + authorize, + ); err != nil { + return err + } + + if !authorize { + // remove any votes casted by the removed validator + snapshot.RemoveVotesByVoter(candidate.Addr()) + } + + // remove all the votes that promoted this validator + snapshot.RemoveVotesByCandidate(candidate) + } + + return nil +} + +// validatorToMiner converts validator to bytes for miner field in header +func validatorToMiner(validator validators.Validator) ([]byte, error) { + switch validator.(type) { + case *validators.ECDSAValidator: + // Return Address directly + // to support backward compatibility + return validator.Addr().Bytes(), nil + case *validators.BLSValidator: + return validator.Bytes(), nil + default: + return nil, validators.ErrInvalidValidatorType + } +} + +// minerToValidator converts bytes to validator for miner field in header +func minerToValidator( + validatorType validators.ValidatorType, + miner []byte, +) (validators.Validator, error) { + validator, err := validators.NewValidatorFromType(validatorType) + if err != nil { + return nil, err + } + + switch typedVal := validator.(type) { + case *validators.ECDSAValidator: + typedVal.Address = types.BytesToAddress(miner) + case *validators.BLSValidator: + if err := typedVal.SetFromBytes(miner); err != nil { + return nil, err + } + default: + // shouldn't reach here + return nil, validators.ErrInvalidValidatorType + } + + return validator, nil +} diff --git a/validators/store/snapshot/snapshot_test.go b/validators/store/snapshot/snapshot_test.go new file mode 100644 index 0000000000..ac81ae3d03 --- /dev/null +++ b/validators/store/snapshot/snapshot_test.go @@ -0,0 +1,2802 @@ +package snapshot + +import ( + "errors" + "fmt" + "math/big" + "sync" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + testHelper "github.com/0xPolygon/polygon-edge/helper/tests" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/assert" +) + +var ( + errTest = errors.New("test error") +) + +// fakeValidator is a invalid validator +type fakeValidator struct { + validators.Validator +} + +func (f *fakeValidator) Addr() types.Address { + return types.ZeroAddress +} + +type mockSigner struct { + TypeFn func() validators.ValidatorType + EcrecoverFromHeaderFn func(*types.Header) (types.Address, error) + GetValidatorsFn func(*types.Header) (validators.Validators, error) +} + +func (m *mockSigner) Type() validators.ValidatorType { + return m.TypeFn() +} + +func (m *mockSigner) EcrecoverFromHeader(h *types.Header) (types.Address, error) { + return m.EcrecoverFromHeaderFn(h) +} + +func (m *mockSigner) GetValidators(h *types.Header) (validators.Validators, error) { + return m.GetValidatorsFn(h) +} + +func newTestHeaderHash(height uint64) types.Hash { + return types.BytesToHash(crypto.Keccak256(big.NewInt(int64(height)).Bytes())) +} + +func newTestHeader(height uint64, miner []byte, nonce types.Nonce) *types.Header { + return &types.Header{ + Number: height, + Hash: newTestHeaderHash(height), + Miner: miner, + Nonce: nonce, + } +} + +func newMockBlockchain(latestHeight uint64, headers map[uint64]*types.Header) store.HeaderGetter { + return &store.MockBlockchain{ + HeaderFn: func() *types.Header { + return headers[latestHeight] + }, + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + header, ok := headers[height] + + return header, ok + }, + } +} + +func newTestSnapshotValidatorStore( + blockchain store.HeaderGetter, + getSigner func(uint64) (SignerInterface, error), + lastBlock uint64, + snapshots []*Snapshot, + candidates []*store.Candidate, + epochSize uint64, +) *SnapshotValidatorStore { + return &SnapshotValidatorStore{ + logger: hclog.NewNullLogger(), + store: newSnapshotStore( + &SnapshotMetadata{ + LastBlock: lastBlock, + }, + snapshots, + ), + blockchain: blockchain, + getSigner: getSigner, + candidates: candidates, + candidatesLock: sync.RWMutex{}, + epochSize: epochSize, + } +} + +func TestNewSnapshotValidatorStore(t *testing.T) { + t.Parallel() + + var ( + logger = hclog.NewNullLogger() + blockchain = newMockBlockchain( + 0, + map[uint64]*types.Header{ + 0: newTestHeader( + 0, + types.ZeroAddress.Bytes(), + types.Nonce{}, + ), + }, + ) + + epochSize uint64 = 10 + metadata = &SnapshotMetadata{ + LastBlock: 20, + } + snapshots = []*Snapshot{} + ) + + t.Run("should return error", func(t *testing.T) { + t.Parallel() + + store, err := NewSnapshotValidatorStore( + logger, + blockchain, + func(u uint64) (SignerInterface, error) { + return nil, errTest + }, + epochSize, + metadata, + snapshots, + ) + + assert.Nil( + t, + store, + ) + + assert.Equal( + t, + errTest, + err, + ) + }) + + t.Run("should succeed", func(t *testing.T) { + t.Parallel() + + vals := validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + + getSigner := func(u uint64) (SignerInterface, error) { + return &mockSigner{ + GetValidatorsFn: func(h *types.Header) (validators.Validators, error) { + return vals, nil + }, + }, nil + } + + snapshotStore, err := NewSnapshotValidatorStore( + logger, + blockchain, + getSigner, + epochSize, + metadata, + snapshots, + ) + + assert.Equal( + t, + snapshotStore.store, + newSnapshotStore(metadata, []*Snapshot{ + { + Number: 0, + Hash: newTestHeaderHash(0).String(), + Set: vals, + Votes: []*store.Vote{}, + }, + }), + ) + + assert.Equal( + t, + make([]*store.Candidate, 0), + snapshotStore.candidates, + ) + + assert.Equal( + t, + snapshotStore.epochSize, + epochSize, + ) + + assert.NoError( + t, + err, + ) + }) +} + +func TestSnapshotValidatorStore_initialize(t *testing.T) { + t.Parallel() + + var ( + initialCandidates = []*store.Candidate{} + epochSize uint64 = 10 + ) + + newGetSigner := func( + validatorType validators.ValidatorType, + headerCreators map[uint64]types.Address, + headerValidators map[uint64]validators.Validators, + ) func(uint64) (SignerInterface, error) { + return func(u uint64) (SignerInterface, error) { + return &mockSigner{ + TypeFn: func() validators.ValidatorType { + return validatorType + }, + EcrecoverFromHeaderFn: func(h *types.Header) (types.Address, error) { + creator, ok := headerCreators[h.Number] + if !ok { + return types.ZeroAddress, errTest + } + + return creator, nil + }, + GetValidatorsFn: func(h *types.Header) (validators.Validators, error) { + validators, ok := headerValidators[h.Number] + if !ok { + return nil, errTest + } + + return validators, nil + }, + }, nil + } + } + + tests := []struct { + name string + latestHeaderNumber uint64 + headers map[uint64]*types.Header + headerCreators map[uint64]types.Address + headerValidators map[uint64]validators.Validators + validatorType validators.ValidatorType + initialLastHeight uint64 + initialSnapshots []*Snapshot + expectedErr error + finalLastHeight uint64 + finalSnapshots []*Snapshot + }{ + { + name: "should a add snapshot created by genesis", + latestHeaderNumber: 0, + headers: map[uint64]*types.Header{ + 0: newTestHeader( + 0, + types.ZeroAddress.Bytes(), + types.Nonce{}, + ), + }, + headerCreators: nil, + headerValidators: map[uint64]validators.Validators{ + 0: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + validatorType: validators.ECDSAValidatorType, + initialLastHeight: 0, + initialSnapshots: []*Snapshot{}, + expectedErr: nil, + finalLastHeight: 0, + finalSnapshots: []*Snapshot{ + { + Number: 0, + Hash: newTestHeaderHash(0).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + }, + { + name: "should add a snapshot on the latest epoch if initial snapshots are empty", + latestHeaderNumber: 20, + headers: map[uint64]*types.Header{ + 20: newTestHeader( + 20, + types.ZeroAddress.Bytes(), + types.Nonce{}, + ), + }, + headerCreators: nil, + headerValidators: map[uint64]validators.Validators{ + 20: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + validatorType: validators.ECDSAValidatorType, + initialLastHeight: 10, + initialSnapshots: []*Snapshot{}, + expectedErr: nil, + finalLastHeight: 20, + finalSnapshots: []*Snapshot{ + { + Number: 20, + Hash: newTestHeaderHash(20).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + }, + { + name: "should add a snapshot on the latest epoch if the latest snapshot is not for the latest epoch", + latestHeaderNumber: 20, + headers: map[uint64]*types.Header{ + 20: newTestHeader( + 20, + types.ZeroAddress.Bytes(), + types.Nonce{}, + ), + }, + headerCreators: nil, + headerValidators: map[uint64]validators.Validators{ + 20: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + validatorType: validators.ECDSAValidatorType, + initialLastHeight: 10, + initialSnapshots: []*Snapshot{ + { + Number: 10, + Hash: newTestHeaderHash(10).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + expectedErr: nil, + finalLastHeight: 20, + finalSnapshots: []*Snapshot{ + { + Number: 10, + Hash: newTestHeaderHash(10).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + { + Number: 20, + Hash: newTestHeaderHash(20).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + }, + { + name: "should catch up latest header", + latestHeaderNumber: 22, + headers: map[uint64]*types.Header{ + 20: newTestHeader( + 20, + types.ZeroAddress.Bytes(), + types.Nonce{}, + ), + 21: newTestHeader( + 21, + ecdsaValidator3.Address.Bytes(), + nonceAuthVote, + ), + 22: newTestHeader( + 22, + ecdsaValidator1.Address.Bytes(), + nonceDropVote, + ), + }, + headerCreators: map[uint64]types.Address{ + 21: ecdsaValidator1.Address, + 22: ecdsaValidator2.Address, + }, + headerValidators: map[uint64]validators.Validators{ + 20: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + validatorType: validators.ECDSAValidatorType, + initialLastHeight: 20, + initialSnapshots: []*Snapshot{ + { + Number: 20, + Hash: newTestHeaderHash(20).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + expectedErr: nil, + finalLastHeight: 22, + finalSnapshots: []*Snapshot{ + { + Number: 20, + Hash: newTestHeaderHash(20).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + { + Number: 21, + Hash: newTestHeaderHash(21).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{ + { + Candidate: ecdsaValidator3, + Validator: ecdsaValidator1.Address, + Authorize: true, + }, + }, + }, + { + Number: 22, + Hash: newTestHeaderHash(22).String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{ + { + Candidate: ecdsaValidator3, + Validator: ecdsaValidator1.Address, + Authorize: true, + }, + { + Candidate: ecdsaValidator1, + Validator: ecdsaValidator2.Address, + Authorize: false, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + newMockBlockchain(test.latestHeaderNumber, test.headers), + newGetSigner(test.validatorType, test.headerCreators, test.headerValidators), + test.initialLastHeight, + test.initialSnapshots, + initialCandidates, + epochSize, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + snapshotStore.initialize(), + ) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + assert.Equal( + t, + test.finalLastHeight, + snapshotStore.GetSnapshotMetadata().LastBlock, + ) + assert.Equal( + t, + initialCandidates, + snapshotStore.candidates, + ) + }) + } +} + +func TestSnapshotValidatorStoreSourceType(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 0, + nil, + nil, + 0, + ) + + assert.Equal( + t, + store.Snapshot, + snapshotStore.SourceType(), + ) +} + +func TestSnapshotValidatorStoreGetSnapshotMetadata(t *testing.T) { + t.Parallel() + + var ( + lastBlock = uint64(10) + + snapshotStore = newTestSnapshotValidatorStore( + nil, + nil, + lastBlock, + nil, + nil, + 0, + ) + ) + + assert.Equal( + t, + &SnapshotMetadata{ + LastBlock: lastBlock, + }, + snapshotStore.GetSnapshotMetadata(), + ) +} + +func TestSnapshotValidatorStoreGetSnapshots(t *testing.T) { + t.Parallel() + + var ( + snapshots = []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + } + + snapshotStore = newTestSnapshotValidatorStore( + nil, + nil, + 0, + snapshots, + nil, + 0, + ) + ) + + assert.Equal( + t, + snapshots, + snapshotStore.GetSnapshots(), + ) +} + +func TestSnapshotValidatorStoreCandidates(t *testing.T) { + t.Parallel() + + var ( + candidates = []*store.Candidate{ + { + Validator: ecdsaValidator1, + Authorize: true, + }, + } + + snapshotStore = newTestSnapshotValidatorStore( + nil, + nil, + 0, + nil, + nil, + 0, + ) + ) + + snapshotStore.candidates = candidates + + assert.Equal( + t, + candidates, + snapshotStore.Candidates(), + ) +} + +func TestSnapshotValidatorStoreGetValidators(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshots []*Snapshot + height uint64 + expectedRes validators.Validators + expectedErr error + }{ + { + name: "should return ErrSnapshotNotFound is the list is empty", + snapshots: []*Snapshot{}, + height: 10, + expectedRes: nil, + expectedErr: ErrSnapshotNotFound, + }, + { + name: "should return validators in the Snapshot for the given height", + snapshots: []*Snapshot{ + {Number: 10}, + { + Number: 20, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + {Number: 30}, + }, + height: 25, + expectedRes: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 0, + test.snapshots, + nil, + 0, + ) + + res, err := snapshotStore.GetValidatorsByHeight(test.height) + + assert.Equal(t, test.expectedRes, res) + assert.Equal(t, test.expectedErr, err) + }) + } +} + +func TestSnapshotValidatorStoreVotes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshots []*Snapshot + height uint64 + expectedRes []*store.Vote + expectedErr error + }{ + { + name: "should return ErrSnapshotNotFound is the list is empty", + snapshots: []*Snapshot{}, + height: 10, + expectedRes: nil, + expectedErr: ErrSnapshotNotFound, + }, + { + name: "should return validators in the Snapshot for the given height", + snapshots: []*Snapshot{ + {Number: 10}, + { + Number: 20, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + }, + }, + {Number: 30}, + }, + height: 25, + expectedRes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + }, + expectedErr: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 0, + test.snapshots, + nil, + 0, + ) + + res, err := snapshotStore.Votes(test.height) + + assert.Equal(t, test.expectedRes, res) + assert.Equal(t, test.expectedErr, err) + }) + } +} + +func TestSnapshotValidatorStoreUpdateValidatorSet(t *testing.T) { + t.Parallel() + + var ( + // Add a snapshot so that snapshot can be used from the target height + targetHeight uint64 = 21 + + header = newTestHeader(targetHeight-1, nil, types.Nonce{}) + + oldValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ) + + newValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ecdsaValidator3, + ) + ) + + tests := []struct { + name string + initialSnapshots []*Snapshot + blockchain *store.MockBlockchain + // input + newValidators validators.Validators + height uint64 + // output + expectedErr error + finalSnapshots []*Snapshot + }{ + { + name: "should return an error if the blockchain doesn't have the header", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, targetHeight-1, height) + + // not found + return nil, false + }, + }, + newValidators: nil, + height: targetHeight, + expectedErr: fmt.Errorf("header at %d not found", targetHeight-1), + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + }, + { + name: "should replace a new snapshot with the snapshot that has the same height", + initialSnapshots: []*Snapshot{ + {Number: 10}, + { + Number: 20, + Set: oldValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator2.Address, true), + newTestVote(ecdsaValidator3, ecdsaValidator2.Address, true), + }, + }, + }, + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, targetHeight-1, height) + + return header, true + }, + }, + newValidators: newValidators, + height: targetHeight, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + {Number: 10}, + { + Number: header.Number, + Hash: header.Hash.String(), + Set: newValidators, + Votes: []*store.Vote{}, + }, + }, + }, + { + name: "should add a new snapshot when the snapshot with the same height doesn't exist", + initialSnapshots: []*Snapshot{ + {Number: 10}, + }, + blockchain: &store.MockBlockchain{ + GetHeaderByNumberFn: func(height uint64) (*types.Header, bool) { + assert.Equal(t, targetHeight-1, height) + + return header, true + }, + }, + newValidators: newValidators, + height: targetHeight, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + {Number: 10}, + { + Number: header.Number, + Hash: header.Hash.String(), + Set: newValidators, + Votes: []*store.Vote{}, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + test.blockchain, + nil, + 20, + test.initialSnapshots, + nil, + 0, + ) + + err := snapshotStore.UpdateValidatorSet( + test.newValidators, + test.height, + ) + + testHelper.AssertErrorMessageContains(t, test.expectedErr, err) + assert.Equal(t, test.finalSnapshots, snapshotStore.GetSnapshots()) + }) + } +} + +func TestSnapshotValidatorStoreModifyHeader(t *testing.T) { + t.Parallel() + + var ( + targetNumber uint64 = 20 + ) + + newInitialHeader := func() *types.Header { + return newTestHeader(0, types.ZeroAddress.Bytes(), types.Nonce{}) + } + + tests := []struct { + name string + initialSnapshots []*Snapshot + initialCandidates []*store.Candidate + // input + proposer types.Address + // output + expectedErr error + expectedHeader *types.Header + }{ + { + name: "should return ErrSnapshotNotFound if the snapshot not found", + initialSnapshots: []*Snapshot{}, + proposer: addr1, + expectedErr: ErrSnapshotNotFound, + expectedHeader: newInitialHeader(), + }, + { + name: "should return validators.ErrInvalidValidatorType if the candidate is invalid", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: &fakeValidator{}, + Authorize: true, + }, + }, + proposer: addr1, + expectedErr: validators.ErrInvalidValidatorType, + expectedHeader: newTestHeader( + 0, + nil, + types.Nonce{}, + ), + }, + { + name: "should update miner and nonce for the addition", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + proposer: addr1, + expectedErr: nil, + expectedHeader: newTestHeader( + 0, + ecdsaValidator2.Address.Bytes(), + nonceAuthVote, + ), + }, + { + name: "should update miner and nonce for the deletion", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: false, + }, + }, + proposer: addr1, + expectedErr: nil, + expectedHeader: newTestHeader( + 0, + ecdsaValidator2.Address.Bytes(), + nonceDropVote, + ), + }, + { + name: "should ignore the candidate for the addition if the candidate is in the validator set already", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + proposer: addr1, + expectedErr: nil, + expectedHeader: newInitialHeader(), + }, + { + name: "should ignore the candidate for the deletion if the candidate isn't in the validator set", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: false, + }, + }, + proposer: addr1, + expectedErr: nil, + expectedHeader: newInitialHeader(), + }, + { + name: "should ignore the candidate if the candidate has been voted", + initialSnapshots: []*Snapshot{ + { + Number: targetNumber - 1, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + }, + }, + }, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + proposer: addr1, + expectedErr: nil, + expectedHeader: newInitialHeader(), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + header := newInitialHeader() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + test.initialSnapshots, + test.initialCandidates, + 0, + ) + + assert.Equal( + t, + test.expectedErr, + snapshotStore.ModifyHeader( + header, + test.proposer, + ), + ) + + assert.Equal(t, test.expectedHeader, header) + }) + } +} + +func TestSnapshotValidatorStoreVerifyHeader(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + nonce types.Nonce + expectedErr error + }{ + { + name: "should return nil in case of zero value nonce", + // same with nonceDropVote + nonce: types.Nonce{}, + expectedErr: nil, + }, + { + name: "should return nil in case of nonceAuthVote", + nonce: nonceAuthVote, + expectedErr: nil, + }, + { + name: "should return nil in case of nonceDropVote", + nonce: nonceDropVote, + expectedErr: nil, + }, + { + name: "should return ErrInvalidNonce in case of other nonces", + nonce: types.Nonce{0xff, 0x00}, + expectedErr: ErrInvalidNonce, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + header := &types.Header{ + Nonce: test.nonce, + } + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + nil, + nil, + 0, + ) + + assert.Equal( + t, + test.expectedErr, + snapshotStore.VerifyHeader(header), + ) + }) + } +} + +func TestSnapshotValidatorStoreProcessHeadersInRange(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + validatorType = validators.ECDSAValidatorType + + initialValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ) + initialLastHeight uint64 = 0 + initialSnapshot = &Snapshot{ + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{}, + } + initialSnapshots = []*Snapshot{ + initialSnapshot, + } + initialCandidates = []*store.Candidate{} + ) + + createHeaderWithVote := func(height uint64, candidate validators.Validator, nonce types.Nonce) *types.Header { + candidateBytes, _ := validatorToMiner(candidate) + + return &types.Header{ + Number: height, + Miner: candidateBytes, + Nonce: nonce, + } + } + + tests := []struct { + name string + from uint64 + to uint64 + headers map[uint64]*types.Header + headerCreators map[uint64]types.Address + expectedErr error + finalSnapshots []*Snapshot + finalLastHeight uint64 + }{ + { + name: "should return error if header not found", + from: 0, + to: 5, + headers: map[uint64]*types.Header{}, + headerCreators: map[uint64]types.Address{}, + expectedErr: fmt.Errorf("header %d not found", 1), + finalSnapshots: initialSnapshots, + finalLastHeight: initialLastHeight, + }, + { + name: "should return error if ProcessHeader fails", + from: 0, + to: 2, + headers: map[uint64]*types.Header{ + 1: createHeaderWithVote(1, ecdsaValidator2, nonceAuthVote), + 2: createHeaderWithVote(2, ecdsaValidator2, nonceAuthVote), + }, + headerCreators: map[uint64]types.Address{ + 1: ecdsaValidator1.Address, + }, + expectedErr: errTest, + finalSnapshots: []*Snapshot{ + initialSnapshot, + { + Number: 1, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + finalLastHeight: 1, + }, + { + name: "should process all headers for ECDSAValidators", + from: 1, + to: 6, + headers: map[uint64]*types.Header{ + 1: createHeaderWithVote(1, ecdsaValidator2, nonceAuthVote), + 2: createHeaderWithVote(2, ecdsaValidator3, nonceAuthVote), + 3: createHeaderWithVote(3, ecdsaValidator3, nonceAuthVote), + 4: createHeaderWithVote(4, ecdsaValidator2, nonceDropVote), + 5: createHeaderWithVote(5, ecdsaValidator1, nonceDropVote), + 6: createHeaderWithVote(6, ecdsaValidator1, nonceDropVote), + }, + headerCreators: map[uint64]types.Address{ + 1: ecdsaValidator1.Address, + 2: ecdsaValidator2.Address, + 3: ecdsaValidator1.Address, + 4: ecdsaValidator1.Address, + 5: ecdsaValidator2.Address, + 6: ecdsaValidator3.Address, + }, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + initialSnapshot, + { + Number: 1, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + { + Number: 2, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{ + { + Candidate: ecdsaValidator3, + Validator: ecdsaValidator2.Address, + Authorize: true, + }, + }, + }, + { + Number: 3, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ecdsaValidator3, + ), + Votes: []*store.Vote{}, + }, + { + Number: 4, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ecdsaValidator3, + ), + Votes: []*store.Vote{ + { + Candidate: ecdsaValidator2, + Validator: ecdsaValidator1.Address, + Authorize: false, + }, + }, + }, + { + Number: 5, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ecdsaValidator3, + ), + Votes: []*store.Vote{ + { + Candidate: ecdsaValidator2, + Validator: ecdsaValidator1.Address, + Authorize: false, + }, + { + Candidate: ecdsaValidator1, + Validator: ecdsaValidator2.Address, + Authorize: false, + }, + }, + }, + { + Number: 6, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ecdsaValidator3, + ), + Votes: []*store.Vote{}, + }, + }, + finalLastHeight: 6, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + newMockBlockchain(0, test.headers), + func(u uint64) (SignerInterface, error) { + return &mockSigner{ + TypeFn: func() validators.ValidatorType { + return validatorType + }, + EcrecoverFromHeaderFn: func(h *types.Header) (types.Address, error) { + creator, ok := test.headerCreators[h.Number] + if !ok { + return types.ZeroAddress, errTest + } + + return creator, nil + }, + }, nil + }, + initialLastHeight, + initialSnapshots, + initialCandidates, + epochSize, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + snapshotStore.ProcessHeadersInRange(test.from, test.to), + ) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + assert.Equal( + t, + test.finalLastHeight, + snapshotStore.GetSnapshotMetadata().LastBlock, + ) + }) + } +} + +func TestSnapshotValidatorStoreProcessHeader(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + initialLastHeight uint64 = 49 + headerHeight1 uint64 = 50 + headerHeight2 uint64 = 51 + + initialValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + initialCandidates = []*store.Candidate{} + initialSnapshot = &Snapshot{ + Number: initialLastHeight, + Set: initialValidators, + } + ) + + newGetSigner := func( + validatorType validators.ValidatorType, + expectedHeight uint64, + expectedHeader *types.Header, + returnAddress types.Address, + returnError error, + ) func(uint64) (SignerInterface, error) { + t.Helper() + + return func(height uint64) (SignerInterface, error) { + assert.Equal(t, expectedHeight, height) + + return &mockSigner{ + TypeFn: func() validators.ValidatorType { + return validatorType + }, + EcrecoverFromHeaderFn: func(header *types.Header) (types.Address, error) { + assert.Equal(t, expectedHeader, header) + + return returnAddress, returnError + }, + }, nil + } + } + + tests := []struct { + name string + getSigner func(uint64) (SignerInterface, error) + initialSnapshots []*Snapshot + header *types.Header + expectedErr error + finalSnapshots []*Snapshot + finalLastBlock uint64 + }{ + { + name: "should return error if getSigner returns error", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight1, height) + + return nil, errTest + }, + initialSnapshots: []*Snapshot{}, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: errTest, + finalSnapshots: []*Snapshot{}, + finalLastBlock: initialLastHeight, + }, + { + name: "should return error if the signer is nil", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight1, height) + + return nil, nil + }, + initialSnapshots: []*Snapshot{}, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: fmt.Errorf("signer not found at %d", headerHeight1), + finalSnapshots: []*Snapshot{}, + finalLastBlock: initialLastHeight, + }, + { + name: "should return error if EcrecoverFromHeader fails", + getSigner: newGetSigner( + validators.ECDSAValidatorType, + headerHeight1, + &types.Header{Number: headerHeight1}, + types.ZeroAddress, + errTest, + ), + initialSnapshots: []*Snapshot{}, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: errTest, + finalSnapshots: []*Snapshot{}, + finalLastBlock: initialLastHeight, + }, + { + name: "should return error if snapshot not found", + getSigner: newGetSigner( + validators.ECDSAValidatorType, + headerHeight1, + &types.Header{Number: headerHeight1}, + ecdsaValidator3.Address, + nil, + ), + initialSnapshots: []*Snapshot{}, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: ErrSnapshotNotFound, + finalSnapshots: []*Snapshot{}, + finalLastBlock: initialLastHeight, + }, + { + name: "should return ErrUnauthorizedProposer if the header creator is not the validator in the snapshot", + getSigner: newGetSigner( + validators.ECDSAValidatorType, + headerHeight1, + &types.Header{Number: headerHeight1}, + ecdsaValidator3.Address, + nil, + ), + initialSnapshots: []*Snapshot{ + initialSnapshot, + }, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: ErrUnauthorizedProposer, + finalSnapshots: []*Snapshot{ + initialSnapshot, + }, + finalLastBlock: initialLastHeight, + }, + { + name: "should reset votes and remove lower snapshots if the height is the beginning of the epoch", + getSigner: newGetSigner( + validators.ECDSAValidatorType, headerHeight1, + &types.Header{Number: headerHeight1}, + ecdsaValidator1.Address, nil, + ), + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + {Number: 40}, + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator1, ecdsaValidator2.Address, false), + }, + }, + }, + header: &types.Header{ + Number: headerHeight1, + }, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + {Number: 30}, + {Number: 40}, + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator1, ecdsaValidator2.Address, false), + }, + }, + { + Number: headerHeight1, + Hash: types.ZeroHash.String(), + Set: initialValidators, + }, + }, + finalLastBlock: headerHeight1, + }, + { + name: "should just update latest height if miner is zero", + getSigner: newGetSigner( + validators.ECDSAValidatorType, + headerHeight2, &types.Header{Number: headerHeight2, Miner: types.ZeroAddress.Bytes()}, + ecdsaValidator1.Address, nil, + ), + initialSnapshots: []*Snapshot{ + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator1, ecdsaValidator2.Address, false), + }, + }, + }, + header: &types.Header{ + Number: headerHeight2, + Miner: types.ZeroAddress.Bytes(), + }, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator1, ecdsaValidator2.Address, false), + }, + }, + }, + finalLastBlock: headerHeight2, + }, + { + name: "should process the vote in the header and update snapshots and latest height", + getSigner: newGetSigner( + validators.ECDSAValidatorType, headerHeight2, &types.Header{ + Number: headerHeight2, + Miner: ecdsaValidator3.Address.Bytes(), + Nonce: nonceAuthVote, + }, ecdsaValidator1.Address, nil, + ), + initialSnapshots: []*Snapshot{ + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator2.Address, true), + }, + }, + }, + header: &types.Header{ + Number: headerHeight2, + Miner: ecdsaValidator3.Address.Bytes(), + Nonce: nonceAuthVote, + }, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + { + Number: initialLastHeight, + Set: initialValidators, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator2.Address, true), + }, + }, + { + Number: headerHeight2, + Hash: types.ZeroHash.String(), + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ecdsaValidator3, + ), + Votes: []*store.Vote{}, + }, + }, + finalLastBlock: headerHeight2, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + test.getSigner, + initialLastHeight, + test.initialSnapshots, + initialCandidates, + epochSize, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + snapshotStore.ProcessHeader( + test.header, + ), + ) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + + assert.Equal( + t, + test.finalLastBlock, + snapshotStore.GetSnapshotMetadata().LastBlock, + ) + }) + } +} + +func TestSnapshotValidatorStorePropose(t *testing.T) { + t.Parallel() + + var ( + latestHeight uint64 = 20 + ) + + tests := []struct { + name string + initialSnapshots []*Snapshot + initialCandidates []*store.Candidate + candidate validators.Validator + auth bool + proposer types.Address + expectedErr error + finalCandidates []*store.Candidate + }{ + { + name: "should return ErrAlreadyCandidate if the candidate exists in the candidates already", + initialSnapshots: nil, + initialCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + candidate: ecdsaValidator2, + auth: true, + proposer: ecdsaValidator1.Address, + expectedErr: ErrAlreadyCandidate, + finalCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + }, + { + name: "should return ErrSnapshotNotFound if snapshot not found", + initialSnapshots: []*Snapshot{}, + initialCandidates: []*store.Candidate{}, + candidate: ecdsaValidator2, + auth: true, + proposer: ecdsaValidator1.Address, + expectedErr: ErrSnapshotNotFound, + finalCandidates: []*store.Candidate{}, + }, + { + name: "should return ErrCandidateIsValidator if the candidate for addition exists in the validator set already", + initialSnapshots: []*Snapshot{ + { + Number: latestHeight, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + }, + initialCandidates: []*store.Candidate{}, + candidate: ecdsaValidator2, + auth: true, + proposer: ecdsaValidator1.Address, + expectedErr: ErrCandidateIsValidator, + finalCandidates: []*store.Candidate{}, + }, + { + name: "should return ErrCandidateNotExistInSet if the candidate for deletion doesn't exist in the validator set", + initialSnapshots: []*Snapshot{ + { + Number: latestHeight, + Set: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + }, + }, + initialCandidates: []*store.Candidate{}, + candidate: blsValidator3, + auth: false, + proposer: blsValidator1.Address, + expectedErr: ErrCandidateNotExistInSet, + finalCandidates: []*store.Candidate{}, + }, + { + name: "should return ErrAlreadyVoted if the proposer has voted for the same candidate", + initialSnapshots: []*Snapshot{ + { + Number: latestHeight, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + }, + }, + }, + initialCandidates: []*store.Candidate{}, + candidate: ecdsaValidator3, + auth: true, + proposer: ecdsaValidator1.Address, + expectedErr: ErrAlreadyVoted, + finalCandidates: []*store.Candidate{}, + }, + { + name: "should add a new candidate", + initialSnapshots: []*Snapshot{ + { + Number: latestHeight, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + Votes: []*store.Vote{}, + }, + }, + initialCandidates: []*store.Candidate{}, + candidate: ecdsaValidator3, + auth: true, + proposer: ecdsaValidator1.Address, + expectedErr: nil, + finalCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator3, + Authorize: true, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + latestHeight, + test.initialSnapshots, + test.initialCandidates, + 0, + ) + + assert.Equal( + t, + test.expectedErr, + snapshotStore.Propose( + test.candidate, + test.auth, + test.proposer, + ), + ) + }) + } +} + +func TestSnapshotValidatorStore_addCandidate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + initialCandidates []*store.Candidate + // input + validators validators.Validators + candidate validators.Validator + authorize bool + // output + expectedErr error + finalCandidates []*store.Candidate + }{ + { + name: "should add a new candidate for addition", + initialCandidates: []*store.Candidate{}, + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + candidate: ecdsaValidator2, + authorize: true, + expectedErr: nil, + finalCandidates: []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + }, + }, + { + name: "should return ErrCandidateNotExistInSet if the candidate to be removed doesn't exist in set", + initialCandidates: []*store.Candidate{}, + validators: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + candidate: ecdsaValidator2, + authorize: false, + expectedErr: ErrCandidateNotExistInSet, + finalCandidates: []*store.Candidate{}, + }, + { + name: "should add a new candidate for deletion", + initialCandidates: []*store.Candidate{}, + validators: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + // candidate just has to have the Address field only + candidate: validators.NewBLSValidator(blsValidator2.Addr(), nil), + authorize: false, + expectedErr: nil, + finalCandidates: []*store.Candidate{ + { + Validator: blsValidator2, + Authorize: false, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + nil, + test.initialCandidates, + 0, + ) + + assert.Equal( + t, + test.expectedErr, + snapshotStore.addCandidate( + test.validators, + test.candidate, + test.authorize, + ), + ) + + assert.Equal( + t, + test.finalCandidates, + snapshotStore.candidates, + ) + }) + } +} + +func TestSnapshotValidatorStore_addHeaderSnap(t *testing.T) { + t.Parallel() + + var ( + headerHeight uint64 = 10 + headerHash = types.BytesToHash(crypto.Keccak256([]byte{byte(headerHeight)})) + header = &types.Header{ + Number: headerHeight, + Hash: headerHash, + } + + newValidators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + ) + + tests := []struct { + name string + getSigner func(uint64) (SignerInterface, error) + initialSnapshots []*Snapshot + header *types.Header + finalSnapshots []*Snapshot + expectedErr error + }{ + { + name: "should return error if getSigner fails", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight, height) + + return nil, errTest + }, + initialSnapshots: []*Snapshot{}, + header: header, + expectedErr: errTest, + finalSnapshots: []*Snapshot{}, + }, + { + name: "should return error if getSigner returns nil", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight, height) + + return nil, nil + }, + initialSnapshots: []*Snapshot{}, + header: header, + expectedErr: fmt.Errorf("signer not found %d", headerHeight), + finalSnapshots: []*Snapshot{}, + }, + { + name: "should return error if signer.GetValidators fails", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight, height) + + return &mockSigner{ + GetValidatorsFn: func(h *types.Header) (validators.Validators, error) { + return nil, errTest + }, + }, nil + }, + initialSnapshots: []*Snapshot{}, + header: header, + expectedErr: errTest, + finalSnapshots: []*Snapshot{}, + }, + { + name: "should add a new snapshot", + getSigner: func(height uint64) (SignerInterface, error) { + assert.Equal(t, headerHeight, height) + + return &mockSigner{ + GetValidatorsFn: func(h *types.Header) (validators.Validators, error) { + return newValidators, nil + }, + }, nil + }, + initialSnapshots: []*Snapshot{}, + header: header, + expectedErr: nil, + finalSnapshots: []*Snapshot{ + { + Number: headerHeight, + Hash: headerHash.String(), + Votes: []*store.Vote{}, + Set: newValidators, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + test.getSigner, + 20, + test.initialSnapshots, + nil, + 0, + ) + + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + snapshotStore.addHeaderSnap( + test.header, + ), + ) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + }) + } +} + +func TestSnapshotValidatorStore_getSnapshot(t *testing.T) { + t.Parallel() + + var ( + snapthots = []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + } + + expectedSnapshot = &Snapshot{ + Number: 20, + } + + targetHeight uint64 = 20 + ) + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + snapthots, + nil, + 0, + ) + + assert.Equal( + t, + expectedSnapshot, + snapshotStore.getSnapshot(targetHeight), + ) +} + +func TestSnapshotValidatorStore_getLatestSnapshot(t *testing.T) { + t.Parallel() + + var ( + snapthots = []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + } + + expectedSnapshot = &Snapshot{ + Number: 10, + } + + latestHeight uint64 = 11 + ) + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + latestHeight, + snapthots, + nil, + 0, + ) + + assert.Equal( + t, + expectedSnapshot, + snapshotStore.getLatestSnapshot(), + ) +} + +func TestSnapshotValidatorStore_cleanObsoleteCandidates(t *testing.T) { + t.Parallel() + + var ( + validators = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ) + + initialCandidates = []*store.Candidate{ + { + Validator: ecdsaValidator1, + Authorize: true, + }, + { + Validator: ecdsaValidator1, + Authorize: false, + }, + { + Validator: ecdsaValidator2, + Authorize: true, + }, + { + Validator: ecdsaValidator2, + Authorize: false, + }, + } + + finalCandidates = []*store.Candidate{ + { + Validator: ecdsaValidator1, + Authorize: false, + }, + { + Validator: ecdsaValidator2, + Authorize: true, + }, + } + ) + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 0, + nil, + initialCandidates, + 0, + ) + + snapshotStore.cleanObsoleteCandidates(validators) + + assert.Equal( + t, + finalCandidates, + snapshotStore.candidates, + ) +} + +func TestSnapshotValidatorStore_pickOneCandidate(t *testing.T) { + t.Parallel() + + var ( + proposer = ecdsaValidator1.Addr() + + candidates = []*store.Candidate{ + { + Validator: ecdsaValidator2, + Authorize: true, + }, + { + Validator: ecdsaValidator3, + Authorize: true, + }, + } + + snapshot = &Snapshot{ + Votes: []*store.Vote{ + // validator1 has voted to validator2 already + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + }, + } + + expected = &store.Candidate{ + Validator: ecdsaValidator3, + Authorize: true, + } + ) + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 0, + nil, + candidates, + 0, + ) + + candidate := snapshotStore.pickOneCandidate(snapshot, proposer) + + assert.Equal( + t, + expected, + candidate, + ) +} + +func TestSnapshotValidatorStore_saveSnapshotIfChanged(t *testing.T) { + t.Parallel() + + var ( + headerHeight uint64 = 30 + headerHash = types.BytesToHash(crypto.Keccak256([]byte{byte(headerHeight)})) + header = &types.Header{ + Number: headerHeight, + Hash: headerHash, + } + + parentVals = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ) + + newVals = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + + parentVotes = []*store.Vote{} + + newVotes = []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + } + ) + + tests := []struct { + name string + initialSnapshots []*Snapshot + parentSnapshot *Snapshot + snapshot *Snapshot + finalSnapshots []*Snapshot + }{ + { + name: "shouldn't add a new snapshot if the snapshot equals to the parent snapshot", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + parentSnapshot: &Snapshot{Number: 20, Set: parentVals, Votes: parentVotes}, + snapshot: &Snapshot{Number: headerHeight, Set: parentVals, Votes: parentVotes}, + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + }, + { + name: "should add a new snapshot if the snapshot equals to the parent snapshot", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + parentSnapshot: &Snapshot{ + Number: 20, + Set: parentVals, + Votes: parentVotes, + }, + snapshot: &Snapshot{ + Number: headerHeight, + Hash: header.Hash.String(), + Set: newVals, + Votes: newVotes, + }, + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + { + Number: headerHeight, + Hash: header.Hash.String(), + Set: newVals, + Votes: newVotes, + }, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + test.initialSnapshots, + nil, + 0, + ) + + snapshotStore.saveSnapshotIfChanged(test.parentSnapshot, test.snapshot, header) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + }) + } +} + +func TestSnapshotValidatorStore_resetSnapshot(t *testing.T) { + t.Parallel() + + var ( + headerHeight uint64 = 30 + headerHash = types.BytesToHash(crypto.Keccak256([]byte{byte(headerHeight)})) + header = &types.Header{ + Number: headerHeight, + Hash: headerHash, + } + + vals = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ) + + parentVotes = []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Address, true), + } + ) + + tests := []struct { + name string + initialSnapshots []*Snapshot + parentSnapshot *Snapshot + snapshot *Snapshot + finalSnapshots []*Snapshot + }{ + { + name: "should add a new snapshot without votes if the parent snapshot has votes", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + parentSnapshot: &Snapshot{Number: 20, Set: vals, Votes: parentVotes}, + snapshot: &Snapshot{Number: headerHeight, Set: vals, Votes: parentVotes}, + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + { + Number: headerHeight, + Hash: headerHash.String(), + Set: vals, + Votes: nil, + }, + }, + }, + { + name: "shouldn't add if the parent snapshot doesn't have votes", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + parentSnapshot: &Snapshot{Number: 20, Set: vals, Votes: []*store.Vote{}}, + snapshot: &Snapshot{Number: headerHeight, Set: vals, Votes: parentVotes}, + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + test.initialSnapshots, + nil, + 0, + ) + + snapshotStore.resetSnapshot(test.parentSnapshot, test.snapshot, header) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + }) + } +} + +func TestSnapshotValidatorStore_removeLowerSnapshots(t *testing.T) { + t.Parallel() + + var ( + epochSize uint64 = 10 + ) + + tests := []struct { + name string + initialSnapshots []*Snapshot + height uint64 + finalSnapshots []*Snapshot + }{ + { + name: "should remove the old snapshots", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + {Number: 40}, + {Number: 50}, + }, + height: 51, // the beginning of the current epoch is 50 + finalSnapshots: []*Snapshot{ + {Number: 30}, + {Number: 40}, + {Number: 50}, + }, + }, + { + name: "shouldn't remove in case of epoch 0-2", + initialSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + height: 20, + finalSnapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + snapshotStore := newTestSnapshotValidatorStore( + nil, + nil, + 20, + test.initialSnapshots, + nil, + epochSize, + ) + + snapshotStore.removeLowerSnapshots(test.height) + + assert.Equal( + t, + test.finalSnapshots, + snapshotStore.GetSnapshots(), + ) + }) + } +} + +func TestSnapshotValidatorStore_processVote(t *testing.T) { + var ( + headerNumber uint64 = 21 + + initialECDSAValidatorSet = validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ) + + initialBLSValidatorSet = validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ) + ) + + tests := []struct { + name string + header *types.Header + candidateType validators.ValidatorType + proposer types.Address + snapshot *Snapshot + expectedErr error + expectedSnapshot *Snapshot + }{ + { + name: "should return ErrIncorrectNonce if header.Nonce is invalid", + header: &types.Header{ + Nonce: types.Nonce{0x01}, + }, + proposer: types.ZeroAddress, + snapshot: nil, + expectedErr: ErrIncorrectNonce, + expectedSnapshot: nil, + }, + { + name: "should return ErrInvalidValidatorType if the signer returns invalid type", + header: &types.Header{ + Nonce: nonceAuthVote, + }, + candidateType: validators.ValidatorType("fake type"), + proposer: types.ZeroAddress, + snapshot: nil, + expectedErr: validators.ErrInvalidValidatorType, + expectedSnapshot: nil, + }, + { + name: "should return error when failing parse Miner field as a validator", + header: &types.Header{ + Nonce: nonceAuthVote, + Miner: []byte{0x1, 0x1}, + }, + candidateType: validators.BLSValidatorType, + proposer: types.ZeroAddress, + snapshot: nil, + expectedErr: errors.New("value is not of type array"), + expectedSnapshot: nil, + }, + { + name: "should update latest block height if the ECDSA candidate for addition is in the validator set already", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceAuthVote, + Miner: ecdsaValidator2.Address.Bytes(), + }, + candidateType: validators.ECDSAValidatorType, + proposer: types.ZeroAddress, + snapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + }, + expectedErr: nil, + expectedSnapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + }, + }, + { + name: "should update latest block height if the BLS candidate for deletion isn't in the validator set", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceDropVote, + Miner: blsValidator3.Bytes(), + }, + candidateType: validators.BLSValidatorType, + proposer: types.ZeroAddress, + snapshot: &Snapshot{ + Set: initialBLSValidatorSet, + }, + expectedErr: nil, + expectedSnapshot: &Snapshot{ + Set: initialBLSValidatorSet, + }, + }, + { + name: "should return ErrMultipleVotesBySameValidator" + + " if the snapshot has multiple votes for the same candidate by the same proposer", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceAuthVote, + Miner: ecdsaValidator3.Bytes(), + }, + candidateType: validators.ECDSAValidatorType, + proposer: ecdsaValidator1.Address, + snapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + Votes: []*store.Vote{ + // duplicated votes + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + }, + }, + expectedErr: ErrMultipleVotesBySameValidator, + expectedSnapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + }, + }, + }, + { + name: "should add a vote to the snapshot and save in the snapshots", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceAuthVote, + Miner: ecdsaValidator3.Bytes(), + }, + candidateType: validators.ECDSAValidatorType, + proposer: ecdsaValidator1.Address, + snapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + Votes: []*store.Vote{}, + }, + expectedErr: nil, + expectedSnapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Address, true), + }, + }, + }, + { + name: "should drop a BLS validator from validator set and remove the all votes by the deleted validator", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceDropVote, + Miner: blsValidator2.Bytes(), + }, + candidateType: validators.BLSValidatorType, + proposer: blsValidator1.Address, + snapshot: &Snapshot{ + Set: initialBLSValidatorSet, + Votes: []*store.Vote{ + // Votes by Validator 1 + { + Candidate: blsValidator3, + Validator: blsValidator1.Address, + Authorize: true, + }, + // Votes by Validator 2 + { + Candidate: blsValidator2, + Validator: blsValidator2.Address, + Authorize: false, + }, + { + Candidate: blsValidator3, + Validator: blsValidator2.Address, + Authorize: true, + }, + }, + }, + expectedErr: nil, + expectedSnapshot: &Snapshot{ + Set: validators.NewBLSValidatorSet( + blsValidator1, + ), + Votes: []*store.Vote{ + // keep only the votes by validator 1 + { + Candidate: blsValidator3, + Validator: blsValidator1.Address, + Authorize: true, + }, + }, + }, + }, + { + name: "should add a ECDSA candidate to validator set and clear votes for the candidate", + header: &types.Header{ + Number: headerNumber, + Nonce: nonceAuthVote, + Miner: ecdsaValidator3.Bytes(), + }, + candidateType: validators.ECDSAValidatorType, + proposer: ecdsaValidator1.Address, + snapshot: &Snapshot{ + Set: initialECDSAValidatorSet, + Votes: []*store.Vote{ + // Validator2 has voted already + { + Candidate: ecdsaValidator3, + Validator: ecdsaValidator2.Address, + Authorize: true, + }, + }, + }, + expectedErr: nil, + expectedSnapshot: &Snapshot{ + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + // add the new validator + ecdsaValidator3, + ), + // clear votes + Votes: []*store.Vote{}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + testHelper.AssertErrorMessageContains( + t, + test.expectedErr, + processVote( + test.snapshot, + test.header, + test.candidateType, + test.proposer, + ), + ) + + assert.Equal( + t, + test.expectedSnapshot, + test.snapshot, + ) + }) + } +} + +func Test_validatorToMiner(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validator validators.Validator + expectedRes []byte + expectedErr error + }{ + { + name: "ECDSAValidator", + validator: ecdsaValidator1, + expectedRes: ecdsaValidator1.Address.Bytes(), + expectedErr: nil, + }, + { + name: "BLSValidator", + validator: blsValidator1, + expectedRes: blsValidator1.Bytes(), + expectedErr: nil, + }, + { + name: "fake validator", + validator: &fakeValidator{}, + expectedRes: nil, + expectedErr: validators.ErrInvalidValidatorType, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := validatorToMiner(test.validator) + + assert.Equal( + t, + test.expectedRes, + res, + ) + + assert.Equal( + t, + test.expectedErr, + err, + ) + }) + } +} + +func Test_minerToValidator(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + validatorType validators.ValidatorType + miner []byte + expectedRes validators.Validator + expectedErr error + }{ + { + name: "ECDSAValidator", + validatorType: validators.ECDSAValidatorType, + miner: ecdsaValidator1.Address.Bytes(), + expectedRes: ecdsaValidator1, + expectedErr: nil, + }, + { + name: "BLSValidator", + validatorType: validators.BLSValidatorType, + miner: blsValidator1.Bytes(), + expectedRes: blsValidator1, + expectedErr: nil, + }, + { + name: "fake validator", + validatorType: validators.ValidatorType("fake"), + miner: ecdsaValidator1.Address.Bytes(), + expectedRes: nil, + expectedErr: validators.ErrInvalidValidatorType, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + res, err := minerToValidator(test.validatorType, test.miner) + + assert.Equal( + t, + test.expectedRes, + res, + ) + + assert.Equal( + t, + test.expectedErr, + err, + ) + }) + } +} diff --git a/validators/store/snapshot/types.go b/validators/store/snapshot/types.go new file mode 100644 index 0000000000..a7f7279801 --- /dev/null +++ b/validators/store/snapshot/types.go @@ -0,0 +1,402 @@ +package snapshot + +import ( + "encoding/json" + "sort" + "sync" + "sync/atomic" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" +) + +// snapshotMetadata defines the metadata for the snapshot +type SnapshotMetadata struct { + // LastBlock represents the latest block in the snapshot + LastBlock uint64 +} + +// Snapshot is the current state at a given point in time for validators and votes +type Snapshot struct { + // block number when the snapshot was created + Number uint64 + + // block hash when the snapshot was created + Hash string + + // votes casted in chronological order + Votes []*store.Vote + + // current set of validators + Set validators.Validators +} + +func (s *Snapshot) MarshalJSON() ([]byte, error) { + jsonData := struct { + Number uint64 + Hash string + Votes []*store.Vote + Type validators.ValidatorType + Set validators.Validators + }{ + Number: s.Number, + Hash: s.Hash, + Votes: s.Votes, + Type: s.Set.Type(), + Set: s.Set, + } + + return json.Marshal(jsonData) +} + +func (s *Snapshot) UnmarshalJSON(data []byte) error { + raw := struct { + Number uint64 + Hash string + Type string + Votes []json.RawMessage + Set json.RawMessage + }{} + + var err error + + if err = json.Unmarshal(data, &raw); err != nil { + return err + } + + s.Number = raw.Number + s.Hash = raw.Hash + + isLegacyFormat := raw.Type == "" + + // determine validators type + valType := validators.ECDSAValidatorType + + if !isLegacyFormat { + if valType, err = validators.ParseValidatorType(raw.Type); err != nil { + return err + } + } + + // Votes + if err := s.unmarshalVotesJSON(valType, raw.Votes); err != nil { + return err + } + + if err := s.unmarshalSetJSON(valType, raw.Set, isLegacyFormat); err != nil { + return err + } + + return nil +} + +// unmarshalVotesJSON is a helper function to unmarshal for Votes field +func (s *Snapshot) unmarshalVotesJSON( + valType validators.ValidatorType, + rawVotes []json.RawMessage, +) error { + votes := make([]*store.Vote, len(rawVotes)) + for idx := range votes { + candidate, err := validators.NewValidatorFromType(valType) + if err != nil { + return err + } + + votes[idx] = &store.Vote{ + Candidate: candidate, + } + + if err := json.Unmarshal(rawVotes[idx], votes[idx]); err != nil { + return err + } + } + + s.Votes = votes + + return nil +} + +// unmarshalSetJSON is a helper function to unmarshal for Set field +func (s *Snapshot) unmarshalSetJSON( + valType validators.ValidatorType, + rawSet json.RawMessage, + isLegacyFormat bool, +) error { + // Set + if isLegacyFormat { + addrs := []types.Address{} + if err := json.Unmarshal(rawSet, &addrs); err != nil { + return err + } + + vals := make([]*validators.ECDSAValidator, len(addrs)) + for idx, addr := range addrs { + vals[idx] = validators.NewECDSAValidator(addr) + } + + s.Set = validators.NewECDSAValidatorSet(vals...) + + return nil + } + + s.Set = validators.NewValidatorSetFromType(valType) + + return json.Unmarshal(rawSet, s.Set) +} + +// Equal checks if two snapshots are equal +func (s *Snapshot) Equal(ss *Snapshot) bool { + // we only check if Votes and Set are equal since Number and Hash + // are only meant to be used for indexing + if len(s.Votes) != len(ss.Votes) { + return false + } + + for indx := range s.Votes { + if !s.Votes[indx].Equal(ss.Votes[indx]) { + return false + } + } + + return s.Set.Equal(ss.Set) +} + +// Count returns the vote tally. +// The count increases if the callback function returns true +func (s *Snapshot) Count(h func(v *store.Vote) bool) (count int) { + for _, v := range s.Votes { + if h(v) { + count++ + } + } + + return +} + +// AddVote adds a vote to snapshot +func (s *Snapshot) AddVote( + voter types.Address, + candidate validators.Validator, + authorize bool, +) { + s.Votes = append(s.Votes, &store.Vote{ + Validator: voter, + Candidate: candidate, + Authorize: authorize, + }) +} + +// Copy makes a copy of the snapshot +func (s *Snapshot) Copy() *Snapshot { + // Do not need to copy Number and Hash + ss := &Snapshot{ + Votes: make([]*store.Vote, len(s.Votes)), + Set: s.Set.Copy(), + } + + for indx, vote := range s.Votes { + ss.Votes[indx] = vote.Copy() + } + + return ss +} + +// CountByCandidateAndVoter is a helper method to count votes by voter address and candidate +func (s *Snapshot) CountByVoterAndCandidate( + voter types.Address, + candidate validators.Validator, +) int { + return s.Count(func(v *store.Vote) bool { + return v.Validator == voter && v.Candidate.Equal(candidate) + }) +} + +// CountByCandidateAndVoter is a helper method to count votes by candidate +func (s *Snapshot) CountByCandidate( + candidate validators.Validator, +) int { + return s.Count(func(v *store.Vote) bool { + return v.Candidate.Equal(candidate) + }) +} + +// RemoveVotes removes the Votes that meet condition defined in the given function +func (s *Snapshot) RemoveVotes(shouldRemoveFn func(v *store.Vote) bool) { + newVotes := make([]*store.Vote, 0, len(s.Votes)) + + for _, vote := range s.Votes { + if shouldRemoveFn(vote) { + continue + } + + newVotes = append(newVotes, vote) + } + + // match capacity with size in order to shrink array + s.Votes = newVotes[:len(newVotes):len(newVotes)] +} + +// RemoveVotesByVoter is a helper method to remove all votes created by specified address +func (s *Snapshot) RemoveVotesByVoter( + address types.Address, +) { + s.RemoveVotes(func(v *store.Vote) bool { + return v.Validator == address + }) +} + +// RemoveVotesByCandidate is a helper method to remove all votes to specified candidate +func (s *Snapshot) RemoveVotesByCandidate( + candidate validators.Validator, +) { + s.RemoveVotes(func(v *store.Vote) bool { + return v.Candidate.Equal(candidate) + }) +} + +// snapshotStore defines the structure of the stored snapshots +type snapshotStore struct { + sync.RWMutex + + // lastNumber is the latest block number stored + lastNumber uint64 + + // list represents the actual snapshot sorted list + list snapshotSortedList +} + +// newSnapshotStore returns a new snapshot store +func newSnapshotStore( + metadata *SnapshotMetadata, + snapshots []*Snapshot, +) *snapshotStore { + store := &snapshotStore{ + list: snapshotSortedList{}, + } + + store.loadData(metadata, snapshots) + + return store +} + +func (s *snapshotStore) loadData( + metadata *SnapshotMetadata, + snapshots []*Snapshot, +) { + if metadata != nil { + s.lastNumber = metadata.LastBlock + } + + for _, snap := range snapshots { + s.add(snap) + } +} + +// getLastBlock returns the latest block number from the snapshot store. [Thread safe] +func (s *snapshotStore) getLastBlock() uint64 { + return atomic.LoadUint64(&s.lastNumber) +} + +// updateLastBlock sets the latest block number in the snapshot store. [Thread safe] +func (s *snapshotStore) updateLastBlock(num uint64) { + atomic.StoreUint64(&s.lastNumber, num) +} + +// deleteLower deletes snapshots that have a block number lower than the passed in parameter +func (s *snapshotStore) deleteLower(num uint64) { + s.Lock() + defer s.Unlock() + + i := sort.Search(len(s.list), func(i int) bool { + return s.list[i].Number >= num + }) + + s.list = s.list[i:] +} + +// find returns the index of the first closest snapshot to the number specified +func (s *snapshotStore) find(num uint64) *Snapshot { + s.RLock() + defer s.RUnlock() + + if len(s.list) == 0 { + return nil + } + + // fast track, check the last item + if last := s.list[len(s.list)-1]; last.Number < num { + return last + } + + // find the index of the element + // whose Number is bigger than or equals to num, and smallest + i := sort.Search(len(s.list), func(i int) bool { + return s.list[i].Number >= num + }) + + if i < len(s.list) { + if i == 0 { + return s.list[0] + } + + if s.list[i].Number == num { + return s.list[i] + } + + return s.list[i-1] + } + + // should not reach here + return nil +} + +// add adds a new snapshot to the snapshot store +func (s *snapshotStore) add(snap *Snapshot) { + s.Lock() + defer s.Unlock() + + // append and sort the list + s.list = append(s.list, snap) + sort.Sort(&s.list) +} + +// putByNumber replaces snapshot if the snapshot whose Number matches with the given snapshot's Number +// otherwise adds the given snapshot to the list +func (s *snapshotStore) putByNumber(snap *Snapshot) { + s.Lock() + defer s.Unlock() + + i := sort.Search(len(s.list), func(i int) bool { + return s.list[i].Number == snap.Number + }) + + if i < len(s.list) { + // replace if found + s.list[i] = snap + + return + } + + // append if not found + s.list = append(s.list, snap) + sort.Sort(&s.list) +} + +// snapshotSortedList defines the sorted snapshot list +type snapshotSortedList []*Snapshot + +// Len returns the size of the sorted snapshot list +func (s snapshotSortedList) Len() int { + return len(s) +} + +// Swap swaps two values in the sorted snapshot list +func (s snapshotSortedList) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Less checks if the element at index I has a lower number than the element at index J +func (s snapshotSortedList) Less(i, j int) bool { + return s[i].Number < s[j].Number +} diff --git a/validators/store/snapshot/types_test.go b/validators/store/snapshot/types_test.go new file mode 100644 index 0000000000..82d48a31ec --- /dev/null +++ b/validators/store/snapshot/types_test.go @@ -0,0 +1,1330 @@ +package snapshot + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/0xPolygon/polygon-edge/crypto" + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/0xPolygon/polygon-edge/validators/store" + "github.com/stretchr/testify/assert" +) + +var ( + testNumber uint64 = 10 + testHash = types.BytesToHash(crypto.Keccak256([]byte{byte(testNumber)})) +) + +func createExampleECDSASnapshotJSON( + hash types.Hash, + number uint64, + voteAuthorize bool, + voteCandidate *validators.ECDSAValidator, + voteValidator types.Address, + setValidator *validators.ECDSAValidator, +) string { + return fmt.Sprintf(`{ + "Hash": "%s", + "Number": %d, + "Type": "%s", + "Votes": [ + { + "Authorize": %t, + "Candidate": { + "Address": "%s" + }, + "Validator": "%s" + } + ], + "Set": [ + { + "Address": "%s" + } + ] + }`, + hash, + number, + validators.ECDSAValidatorType, + voteAuthorize, + voteCandidate.Addr(), + voteValidator, + setValidator.String(), + ) +} + +func createExampleBLSSnapshotJSON( + hash types.Hash, + number uint64, + voteAuthorize bool, + voteCandidate *validators.BLSValidator, + voteValidator types.Address, + setValidator *validators.BLSValidator, +) string { + return fmt.Sprintf(`{ + "Hash": "%s", + "Number": %d, + "Type": "%s", + "Votes": [ + { + "Authorize": %t, + "Candidate": { + "Address": "%s", + "BLSPublicKey": "%s" + }, + "Validator": "%s" + } + ], + "Set": [ + { + "Address": "%s", + "BLSPublicKey": "%s" + } + ] + }`, + hash, + number, + validators.BLSValidatorType, + voteAuthorize, + voteCandidate.Address, + voteCandidate.BLSPublicKey, + voteValidator, + setValidator.Address, + setValidator.BLSPublicKey, + ) +} + +func newTestVote( + candidate validators.Validator, + validator types.Address, + authorize bool, +) *store.Vote { + return &store.Vote{ + Validator: validator, + Candidate: candidate, + Authorize: authorize, + } +} + +func TestSnapshotMarshalJSON(t *testing.T) { + t.Parallel() + + testMarshalJSON := func( + t *testing.T, + data interface{}, + expectedJSON string, // can be beautified + ) { + t.Helper() + + res, err := json.Marshal(data) + + assert.NoError(t, err) + assert.JSONEq( + t, + strings.TrimSpace(expectedJSON), + string(res), + ) + } + + t.Run("ECDSAValidators", func(t *testing.T) { + t.Parallel() + + vote := newTestVote(ecdsaValidator2, addr1, true) + + testMarshalJSON( + t, + &Snapshot{ + Number: testNumber, + Hash: testHash.String(), + Votes: []*store.Vote{ + vote, + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + createExampleECDSASnapshotJSON( + testHash, + testNumber, + vote.Authorize, + ecdsaValidator2, + vote.Validator, + ecdsaValidator1, + ), + ) + }) + + t.Run("BLSValidators", func(t *testing.T) { + t.Parallel() + + vote := newTestVote(blsValidator2, addr1, false) + + testMarshalJSON( + t, + &Snapshot{ + Number: testNumber, + Hash: testHash.String(), + Votes: []*store.Vote{ + vote, + }, + Set: validators.NewBLSValidatorSet( + blsValidator1, + ), + }, + createExampleBLSSnapshotJSON( + testHash, + testNumber, + vote.Authorize, + blsValidator2, + blsValidator1.Addr(), + blsValidator1, + ), + ) + }) +} + +func TestSnapshotUnmarshalJSON(t *testing.T) { + t.Parallel() + + testUnmarshalJSON := func( + t *testing.T, + jsonStr string, + target interface{}, + expected interface{}, + ) { + t.Helper() + + err := json.Unmarshal([]byte(jsonStr), target) + + assert.NoError(t, err) + assert.Equal(t, expected, target) + } + + t.Run("ECDSAValidators", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + createExampleECDSASnapshotJSON( + testHash, + testNumber, + true, + ecdsaValidator1, + ecdsaValidator2.Addr(), + ecdsaValidator2, + ), + &Snapshot{}, + &Snapshot{ + Number: testNumber, + Hash: testHash.String(), + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator2.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + }, + ) + }) + + t.Run("ECDSAValidators (Legacy format)", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + fmt.Sprintf(` + { + "Number": %d, + "Hash": "%s", + "Votes": [ + { + "Validator": "%s", + "Address": "%s", + "Authorize": %t + } + ], + "Set": [ + "%s" + ] + } + `, + testNumber, + testHash, + ecdsaValidator2.Addr(), + ecdsaValidator1.Addr(), + true, + ecdsaValidator2.Addr(), + ), + &Snapshot{}, + &Snapshot{ + Number: testNumber, + Hash: testHash.String(), + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator2.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + }, + ) + }) + + t.Run("BLSValidators", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + createExampleBLSSnapshotJSON( + testHash, + testNumber, + false, + blsValidator1, + ecdsaValidator2.Addr(), + blsValidator2, + ), + &Snapshot{}, + &Snapshot{ + Number: testNumber, + Hash: testHash.String(), + Votes: []*store.Vote{ + newTestVote(blsValidator1, blsValidator2.Addr(), false), + }, + Set: validators.NewBLSValidatorSet( + blsValidator2, + ), + }, + ) + }) + + t.Run("error handling", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + jsonStr string + }{ + { + name: "should return error if UnmarshalJSON for raw failed", + jsonStr: "[]", + }, + { + name: "should error if parsing Type is failed", + jsonStr: `{ + "Number": 0, + "Hash": "0x1", + "Type": "fake", + "Votes": [], + "Set": [] + }`, + }, + { + name: "should error if unmarshal Votes is failed", + jsonStr: `{ + "Number": 0, + "Hash": "0x1", + "Type": "ecdsa", + "Votes": [ + 1 + ], + "Set": [] + }`, + }, + { + name: "should return error if unmarshal Set is failed", + jsonStr: `{ + "Number": 0, + "Hash": "0x1", + "Type": "ecdsa", + "Votes": [], + "Set": [ + 1 + ] + }`, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Error( + t, + json.Unmarshal([]byte(test.jsonStr), &Snapshot{}), + ) + }) + } + }) +} + +func TestSnapshotEqual(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + s1 *Snapshot + s2 *Snapshot + expected bool + }{ + { + name: "should return true if they're equal", + s1: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + s2: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + expected: true, + }, + { + name: "should return false if the sizes of Votes doesn't match with each other", + s1: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + s2: &Snapshot{ + Votes: []*store.Vote{}, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + expected: false, + }, + { + name: "should return false if Votes don't match with each other", + s1: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + s2: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + expected: false, + }, + { + name: "should return true if Sets doesn't match with each other", + s1: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ), + }, + s2: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator2, + ), + }, + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.s1.Equal(test.s2), + ) + }) + } +} + +func TestSnapshotCount(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + fn func(v *store.Vote) bool + expected int + visited []*store.Vote + }{ + { + name: "should return true if they're equal", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator2.Addr(), false), + newTestVote(ecdsaValidator3, ecdsaValidator3.Addr(), true), + }, + }, + fn: func(v *store.Vote) bool { + // count all + return true + }, + expected: 3, + visited: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator2.Addr(), false), + newTestVote(ecdsaValidator3, ecdsaValidator3.Addr(), true), + }, + }, + { + name: "shouldn't count but visit all", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator2, ecdsaValidator2.Addr(), false), + }, + }, + fn: func(v *store.Vote) bool { + // don't count + return false + }, + expected: 0, + visited: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator2, ecdsaValidator2.Addr(), false), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + visited := make([]*store.Vote, 0, len(test.snapshot.Votes)) + + res := test.snapshot.Count(func(v *store.Vote) bool { + visited = append(visited, v) + + return test.fn(v) + }) + + assert.Equal(t, test.expected, res) + assert.Equal(t, test.visited, visited) + }) + } +} + +func TestSnapshotAddVote(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + vote *store.Vote + expected []*store.Vote + }{ + { + name: "should add ECDSA Validator Vote", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + }, + }, + vote: newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), false), + expected: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), false), + }, + }, + { + name: "should add BLS Validator Vote", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + }, + }, + vote: newTestVote(blsValidator2, ecdsaValidator2.Addr(), false), + expected: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator2, ecdsaValidator2.Addr(), false), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + test.snapshot.AddVote( + test.vote.Validator, + test.vote.Candidate, + test.vote.Authorize, + ) + + assert.Equal(t, test.expected, test.snapshot.Votes) + }) + } +} + +func TestSnapshotCopy(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + }{ + { + name: "should copy ECDSA Snapshot", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewECDSAValidatorSet( + ecdsaValidator1, + ecdsaValidator2, + ), + }, + }, + { + name: "should copy BLS Snapshot", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + }, + Set: validators.NewBLSValidatorSet( + blsValidator1, + blsValidator2, + ), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + copied := test.snapshot.Copy() + + // check fields + assert.Equal(t, test.snapshot, copied) + + // check addresses of Set are different + assert.NotSame(t, test.snapshot.Set, copied.Set) + + // check addresses of Votes are different + assert.Equal(t, len(test.snapshot.Votes), len(copied.Votes)) + for idx := range test.snapshot.Votes { + assert.NotSame(t, test.snapshot.Votes[idx], copied.Votes[idx]) + } + }) + } +} + +func TestSnapshotCountByVoterAndCandidate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + voter types.Address + candidate validators.Validator + expected int + }{ + { + name: "should return count of the votes whose Validator and Candidate equal to the given fields", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), // not match + newTestVote(ecdsaValidator2, ecdsaValidator2.Addr(), true), // not match + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), // match + }, + }, + voter: ecdsaValidator1.Addr(), + candidate: ecdsaValidator2, + expected: 1, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.snapshot.CountByVoterAndCandidate( + test.voter, + test.candidate, + ), + ) + }) + } +} + +func TestSnapshotCountByCandidate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + candidate validators.Validator + expected int + }{ + { + name: "should return count of the votes whose Candidate equal to the given field", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), // match + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), // not match + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), true), // not match + }, + }, + candidate: ecdsaValidator1, + expected: 1, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.snapshot.CountByCandidate( + test.candidate, + ), + ) + }) + } +} + +func TestSnapshotRemoveVotes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + fn func(v *store.Vote) bool + expected []*store.Vote + }{ + { + name: "should remove all Votes from Votes", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), true), + }, + }, + fn: func(v *store.Vote) bool { + // remove all + return true + }, + expected: []*store.Vote{}, + }, + { + name: "should removes only Votes created by Validator 1", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator2, ecdsaValidator2.Addr(), true), + }, + }, + fn: func(v *store.Vote) bool { + return v.Validator == ecdsaValidator1.Address + }, + expected: []*store.Vote{ + newTestVote(blsValidator2, ecdsaValidator2.Addr(), true), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + test.snapshot.RemoveVotes( + test.fn, + ) + + assert.Equal(t, test.expected, test.snapshot.Votes) + // make sure the size and capacity equal with each other + assert.Equal(t, len(test.snapshot.Votes), cap(test.snapshot.Votes)) + }) + } +} + +func TestSnapshotRemoveVotesByVoter(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + voter types.Address + expected []*store.Vote + }{ + { + name: "should remove all Votes", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator2, ecdsaValidator1.Addr(), false), + }, + }, + voter: ecdsaValidator1.Address, + expected: []*store.Vote{}, + }, + { + name: "should removes only Votes created by Validator 1", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), false), + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), false), + }, + }, + voter: ecdsaValidator1.Address, + expected: []*store.Vote{ + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), false), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + test.snapshot.RemoveVotesByVoter( + test.voter, + ) + + assert.Equal(t, test.expected, test.snapshot.Votes) + // make sure the size and capacity equal with each other + assert.Equal(t, len(test.snapshot.Votes), cap(test.snapshot.Votes)) + }) + } +} + +func TestSnapshotRemoveVotesByCandidate(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshot *Snapshot + candidate validators.Validator + expected []*store.Vote + }{ + { + name: "should remove all Votes", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(blsValidator1, ecdsaValidator1.Addr(), true), + newTestVote(blsValidator1, ecdsaValidator2.Addr(), false), + }, + }, + candidate: blsValidator1, + expected: []*store.Vote{}, + }, + { + name: "should removes only Votes for Validator 1", + snapshot: &Snapshot{ + Votes: []*store.Vote{ + newTestVote(ecdsaValidator1, ecdsaValidator1.Addr(), true), + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), false), + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), false), + }, + }, + candidate: ecdsaValidator1, + expected: []*store.Vote{ + newTestVote(ecdsaValidator2, ecdsaValidator1.Addr(), false), + newTestVote(ecdsaValidator3, ecdsaValidator2.Addr(), false), + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + test.snapshot.RemoveVotesByCandidate( + test.candidate, + ) + + assert.Equal(t, test.expected, test.snapshot.Votes) + // make sure the size and capacity equal with each other + assert.Equal(t, len(test.snapshot.Votes), cap(test.snapshot.Votes)) + }) + } +} + +func Test_snapshotSortedListLen(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + list *snapshotSortedList + expected int + }{ + { + name: "should return the size", + list: &snapshotSortedList{ + &Snapshot{}, + &Snapshot{}, + }, + expected: 2, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.list.Len(), + ) + }) + } +} + +func Test_snapshotSortedListSwap(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + list *snapshotSortedList + i, j int + expected *snapshotSortedList + }{ + { + name: "should swap elements", + list: &snapshotSortedList{ + &Snapshot{Number: 3}, + &Snapshot{Number: 2}, + &Snapshot{Number: 1}, + }, + i: 0, + j: 2, + expected: &snapshotSortedList{ + &Snapshot{Number: 1}, + &Snapshot{Number: 2}, + &Snapshot{Number: 3}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + test.list.Swap(test.i, test.j) + + assert.Equal( + t, + test.expected, + test.list, + ) + }) + } +} + +func Test_snapshotSortedListLess(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + list *snapshotSortedList + i, j int + expected bool + }{ + { + name: "should return true when list[i].Number < list[j].Number", + list: &snapshotSortedList{ + &Snapshot{Number: 1}, + &Snapshot{Number: 3}, + }, + expected: true, + }, + { + name: "should return false when list[i].Number == list[j].Number", + list: &snapshotSortedList{ + &Snapshot{Number: 2}, + &Snapshot{Number: 2}, + }, + expected: false, + }, + { + name: "should return false when list[i].Number > list[j].Number", + list: &snapshotSortedList{ + &Snapshot{Number: 2}, + &Snapshot{Number: 1}, + }, + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.list.Less(0, 1), + ) + }) + } +} + +func Test_newSnapshotStore(t *testing.T) { + t.Parallel() + + var ( + metadata = &SnapshotMetadata{ + LastBlock: 10, + } + + snapshots = []*Snapshot{ + {Number: 1}, + {Number: 3}, + } + ) + + assert.Equal( + t, + &snapshotStore{ + lastNumber: metadata.LastBlock, + list: snapshotSortedList( + snapshots, + ), + }, + newSnapshotStore( + metadata, + snapshots, + ), + ) +} + +func Test_snapshotStore_getLastBlock(t *testing.T) { + t.Parallel() + + var ( + metadata = &SnapshotMetadata{ + LastBlock: 10, + } + ) + + store := newSnapshotStore( + metadata, + nil, + ) + + assert.Equal( + t, + metadata.LastBlock, + store.getLastBlock(), + ) +} + +func Test_snapshotStore_updateLastBlock(t *testing.T) { + t.Parallel() + + var ( + metadata = &SnapshotMetadata{ + LastBlock: 10, + } + + newLastBlock = uint64(20) + ) + + store := newSnapshotStore( + metadata, + nil, + ) + + store.updateLastBlock(newLastBlock) + + assert.Equal( + t, + newLastBlock, + store.getLastBlock(), + ) +} + +func Test_snapshotStore_deleteLower(t *testing.T) { + t.Parallel() + + var ( + metadata = &SnapshotMetadata{ + LastBlock: 10, + } + + snapshots = []*Snapshot{ + {Number: 10}, + {Number: 19}, + {Number: 20}, + {Number: 21}, + {Number: 30}, + } + + boundary = uint64(20) + ) + + store := newSnapshotStore( + metadata, + snapshots, + ) + + store.deleteLower(boundary) + + assert.Equal( + t, + &snapshotStore{ + lastNumber: metadata.LastBlock, + list: []*Snapshot{ + {Number: 20}, + {Number: 21}, + {Number: 30}, + }, + }, + store, + ) +} + +func Test_snapshotStore_find(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + snapshots []*Snapshot + input uint64 + expected *Snapshot + }{ + { + name: "should return nil if the list is empty", + snapshots: nil, + input: 1, + expected: nil, + }, + { + name: "should return the last element if it's lower than given number", + snapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + }, + input: 40, + expected: &Snapshot{ + Number: 30, + }, + }, + { + name: "should return the first element if the given value is less than any snapshot", + snapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + }, + input: 5, + expected: &Snapshot{ + Number: 10, + }, + }, + { + name: "should return the element whose Number matches with the given number", + snapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + }, + input: 20, + expected: &Snapshot{ + Number: 20, + }, + }, + { + name: "should return the one before the element whose Number is bigger than the given value", + snapshots: []*Snapshot{ + {Number: 10}, + {Number: 20}, + {Number: 30}, + }, + input: 29, + expected: &Snapshot{ + Number: 20, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + store := newSnapshotStore( + &SnapshotMetadata{}, + test.snapshots, + ) + + assert.Equal( + t, + test.expected, + store.find(test.input), + ) + }) + } +} + +func Test_snapshotStore_add(t *testing.T) { + t.Parallel() + + var ( + snapshots = []*Snapshot{ + {Number: 30}, + {Number: 25}, + {Number: 20}, + {Number: 15}, + {Number: 10}, + } + + newSnapshot = &Snapshot{Number: 12} + + expected = []*Snapshot{ + // should be sorted in asc + {Number: 10}, + {Number: 12}, + {Number: 15}, + {Number: 20}, + {Number: 25}, + {Number: 30}, + } + ) + + store := newSnapshotStore( + &SnapshotMetadata{}, + snapshots, + ) + + store.add(newSnapshot) + + assert.Equal( + t, + &snapshotStore{ + list: snapshotSortedList( + expected, + ), + }, + store, + ) +} + +func Test_snapshotStore_putByNumber(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + initialSnapshots []*Snapshot + newSnapshot *Snapshot + finalSnapshots []*Snapshot + }{ + { + name: "should replace if the same Number snapshot exists in the list", + initialSnapshots: []*Snapshot{ + {Number: 10, Hash: "10"}, + {Number: 20, Hash: "20"}, + {Number: 30, Hash: "30"}, + }, + newSnapshot: &Snapshot{ + Number: 20, + Hash: "xxx", + }, + finalSnapshots: []*Snapshot{ + {Number: 10, Hash: "10"}, + {Number: 20, Hash: "xxx"}, + {Number: 30, Hash: "30"}, + }, + }, + { + name: "should add if the same Number snapshot doesn't exist in the list", + initialSnapshots: []*Snapshot{ + {Number: 10, Hash: "10"}, + {Number: 20, Hash: "20"}, + {Number: 30, Hash: "30"}, + }, + newSnapshot: &Snapshot{ + Number: 25, + Hash: "25", + }, + finalSnapshots: []*Snapshot{ + {Number: 10, Hash: "10"}, + {Number: 20, Hash: "20"}, + {Number: 25, Hash: "25"}, + {Number: 30, Hash: "30"}, + }, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + store := newSnapshotStore( + &SnapshotMetadata{}, + test.initialSnapshots, + ) + + store.putByNumber(test.newSnapshot) + + assert.Equal( + t, + test.finalSnapshots, + []*Snapshot(store.list), + ) + }) + } +} diff --git a/validators/store/test_helper.go b/validators/store/test_helper.go new file mode 100644 index 0000000000..32870f166d --- /dev/null +++ b/validators/store/test_helper.go @@ -0,0 +1,30 @@ +package store + +import ( + "github.com/0xPolygon/polygon-edge/consensus/ibft/signer" + "github.com/0xPolygon/polygon-edge/types" +) + +// Utilities for test +const ( + TestEpochSize = 100 +) + +func NewMockGetSigner(s signer.Signer) func(uint64) (signer.Signer, error) { + return func(u uint64) (signer.Signer, error) { + return s, nil + } +} + +type MockBlockchain struct { + HeaderFn func() *types.Header + GetHeaderByNumberFn func(uint64) (*types.Header, bool) +} + +func (m *MockBlockchain) Header() *types.Header { + return m.HeaderFn() +} + +func (m *MockBlockchain) GetHeaderByNumber(height uint64) (*types.Header, bool) { + return m.GetHeaderByNumberFn(height) +} diff --git a/validators/store/types.go b/validators/store/types.go new file mode 100644 index 0000000000..c995eb5d26 --- /dev/null +++ b/validators/store/types.go @@ -0,0 +1,113 @@ +package store + +import ( + "encoding/json" + "fmt" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" +) + +type ValidatorTypeGetter func(uint64) (validators.ValidatorType, error) + +// Define the type of the validator set +type SourceType string + +const ( + // For validators saved in-memory + Snapshot SourceType = "Snapshot" + + // For validators managed in contract + Contract SourceType = "Contract" +) + +// String is a helper method for casting a SourceType to a string representation +func (t SourceType) String() string { + return string(t) +} + +// ValidatorStore is an interface that ValidatorStore needs to implement +type ValidatorStore interface { + SourceType() SourceType +} + +// HeaderGetter is an interface in order each ValidatorStore gets latest header and header by number +type HeaderGetter interface { + Header() *types.Header + GetHeaderByNumber(uint64) (*types.Header, bool) +} + +// Vote defines the vote structure +type Vote struct { + Validator types.Address // Voter + Candidate validators.Validator // Candidate + Authorize bool // Add or Remove +} + +// Equal checks if two votes are equal +func (v *Vote) Equal(vv *Vote) bool { + if v.Validator != vv.Validator { + return false + } + + if !v.Candidate.Equal(vv.Candidate) { + return false + } + + if v.Authorize != vv.Authorize { + return false + } + + return true +} + +// Copy makes a copy of the vote, and returns it +func (v *Vote) Copy() *Vote { + return &Vote{ + Validator: v.Validator, + Candidate: v.Candidate.Copy(), + Authorize: v.Authorize, + } +} + +// UnmarshalJSON is JSON unmarshaler +func (v *Vote) UnmarshalJSON(data []byte) error { + rawVote := struct { + Validator types.Address // Voter + Authorize bool // Add or Remove + + Address *types.Address // Field in legacy format + Candidate json.RawMessage // New field in new format + }{} + + var err error + + if err = json.Unmarshal(data, &rawVote); err != nil { + return err + } + + v.Validator = rawVote.Validator + v.Authorize = rawVote.Authorize + + // new format + if rawVote.Candidate != nil { + return json.Unmarshal(rawVote.Candidate, v.Candidate) + } + + // legacy format + if rawVote.Address != nil { + ecdsaCandidate, ok := v.Candidate.(*validators.ECDSAValidator) + if !ok { + return fmt.Errorf("expects ECDSAValidator but got %s", v.Candidate.Type()) + } + + ecdsaCandidate.Address = *rawVote.Address + } + + return nil +} + +type Candidate struct { + Validator validators.Validator + Authorize bool +} diff --git a/validators/store/types_test.go b/validators/store/types_test.go new file mode 100644 index 0000000000..b3a36c1f42 --- /dev/null +++ b/validators/store/types_test.go @@ -0,0 +1,347 @@ +package store + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/0xPolygon/polygon-edge/validators" + "github.com/stretchr/testify/assert" +) + +var ( + addr1 = types.StringToAddress("1") + addr2 = types.StringToAddress("2") + addr3 = types.StringToAddress("3") + + testBLSPubKey1 = validators.BLSValidatorPublicKey([]byte("bls_pubkey1")) + + ecdsaValidator1 = validators.NewECDSAValidator(addr1) + ecdsaValidator2 = validators.NewECDSAValidator(addr2) + blsValidator1 = validators.NewBLSValidator(addr1, testBLSPubKey1) +) + +func createExampleECDSAVoteJSON( + authorize bool, + candidate *validators.ECDSAValidator, + validator types.Address, +) string { + return fmt.Sprintf(`{ + "Authorize": %t, + "Candidate": { + "Address": "%s" + }, + "Validator": "%s" + }`, + authorize, + candidate.Addr(), + validator, + ) +} + +func createExampleLegacyECDSAVoteJSON( + authorize bool, + candidate *validators.ECDSAValidator, + validator types.Address, +) string { + return fmt.Sprintf(`{ + "Authorize": %t, + "Address": "%s", + "Validator": "%s" + }`, + authorize, + candidate.Addr(), + validator, + ) +} + +func createExampleBLSVoteJSON( + authorize bool, + candidate *validators.BLSValidator, + validator types.Address, +) string { + return fmt.Sprintf(` + { + "Authorize": %t, + "Candidate": { + "Address": "%s", + "BLSPublicKey": "%s" + }, + "Validator": "%s" + }`, + authorize, + candidate.Address, + candidate.BLSPublicKey, + validator, + ) +} + +func TestSourceTypeString(t *testing.T) { + t.Parallel() + + tests := []struct { + sourceType SourceType + expected string + }{ + { + sourceType: Snapshot, + expected: "Snapshot", + }, + { + sourceType: Contract, + expected: "Contract", + }, + } + + for _, test := range tests { + test := test + + t.Run(test.expected, func(t *testing.T) { + t.Parallel() + + assert.Equal(t, test.expected, test.sourceType.String()) + }) + } +} + +func TestVoteJSONMarshal(t *testing.T) { + t.Parallel() + + testMarshalJSON := func( + t *testing.T, + data interface{}, + expectedJSON string, // can be beautified + ) { + t.Helper() + + res, err := json.Marshal(data) + + assert.NoError(t, err) + assert.JSONEq( + t, + expectedJSON, + string(res), + ) + } + + t.Run("ECDSAValidator", func(t *testing.T) { + t.Parallel() + + testMarshalJSON( + t, + &Vote{ + Authorize: true, + Candidate: ecdsaValidator2, + Validator: addr1, + }, + createExampleECDSAVoteJSON( + true, + ecdsaValidator2, + addr1, + ), + ) + }) + + t.Run("BLSValidator", func(t *testing.T) { + t.Parallel() + + testMarshalJSON( + t, + &Vote{ + Authorize: false, + Candidate: blsValidator1, + Validator: addr2, + }, + createExampleBLSVoteJSON( + false, + blsValidator1, + addr2, + ), + ) + }) +} + +func TestVoteJSONUnmarshal(t *testing.T) { + t.Parallel() + + testUnmarshalJSON := func( + t *testing.T, + jsonStr string, + target interface{}, + expected interface{}, + ) { + t.Helper() + + err := json.Unmarshal([]byte(jsonStr), target) + + assert.NoError(t, err) + assert.Equal(t, expected, target) + } + + t.Run("ECDSAValidator", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + createExampleECDSAVoteJSON( + false, + ecdsaValidator1, + addr2, + ), + &Vote{ + // need to initialize Candidate before unmarshalling + Candidate: new(validators.ECDSAValidator), + }, + &Vote{ + Authorize: false, + Candidate: ecdsaValidator1, + Validator: addr2, + }, + ) + }) + + t.Run("ECDSAValidator (legacy format)", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + createExampleLegacyECDSAVoteJSON( + false, + ecdsaValidator1, + addr2, + ), + &Vote{ + Candidate: new(validators.ECDSAValidator), + }, + &Vote{ + Authorize: false, + Candidate: ecdsaValidator1, + Validator: addr2, + }, + ) + }) + + t.Run("BLSValidator", func(t *testing.T) { + t.Parallel() + + testUnmarshalJSON( + t, + createExampleBLSVoteJSON( + true, + blsValidator1, + addr2, + ), + &Vote{ + // need to initialize Candidate before unmarshalling + Candidate: new(validators.BLSValidator), + }, + &Vote{ + Authorize: true, + Candidate: blsValidator1, + Validator: addr2, + }, + ) + }) +} + +func TestVoteEqual(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + v1 *Vote + v2 *Vote + expected bool + }{ + { + name: "equal", + v1: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + v2: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + expected: true, + }, + { + name: "Validators don't match with each other", + v1: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + v2: &Vote{ + Validator: addr2, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + expected: false, + }, + { + name: "Candidates don't match with each other", + v1: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + v2: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr3), + Authorize: true, + }, + expected: false, + }, + { + name: "Authorizes don't match with each other", + v1: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + }, + v2: &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: false, + }, + expected: false, + }, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + assert.Equal( + t, + test.expected, + test.v1.Equal(test.v2), + ) + }) + } +} + +func TestVoteCopy(t *testing.T) { + t.Parallel() + + v1 := &Vote{ + Validator: addr1, + Candidate: validators.NewECDSAValidator(addr2), + Authorize: true, + } + + v2 := v1.Copy() + + assert.Equal(t, v1, v2) + + // check the addresses are different + assert.NotSame(t, v1.Validator, v2.Validator) + assert.NotSame(t, v1.Candidate, v2.Candidate) + assert.NotSame(t, v1.Authorize, v2.Authorize) +} diff --git a/validators/types.go b/validators/types.go new file mode 100644 index 0000000000..e8a60d17c9 --- /dev/null +++ b/validators/types.go @@ -0,0 +1,91 @@ +package validators + +import ( + "errors" + + "github.com/0xPolygon/polygon-edge/types" + "github.com/umbracle/fastrlp" +) + +var ( + ErrInvalidValidatorType = errors.New("invalid validator type") + ErrMismatchValidatorType = errors.New("mismatch between validator and validators") + ErrMismatchValidatorsType = errors.New("mismatch between two validators") + ErrValidatorAlreadyExists = errors.New("validator already exists in validators") + ErrValidatorNotFound = errors.New("validator not found in validators") + ErrInvalidValidators = errors.New("container is not ") +) + +type ValidatorType string + +const ( + ECDSAValidatorType ValidatorType = "ecdsa" + BLSValidatorType ValidatorType = "bls" +) + +// validatorTypes is the map used for easy string -> ValidatorType lookups +var validatorTypes = map[string]ValidatorType{ + string(ECDSAValidatorType): ECDSAValidatorType, + string(BLSValidatorType): BLSValidatorType, +} + +// ParseValidatorType converts a validatorType string representation to a ValidatorType +func ParseValidatorType(validatorType string) (ValidatorType, error) { + // Check if the cast is possible + castType, ok := validatorTypes[validatorType] + if !ok { + return castType, ErrInvalidValidatorType + } + + return castType, nil +} + +// Validator defines the interface of the methods a validator implements +type Validator interface { + // Return the validator type + Type() ValidatorType + // Return the string representation + String() string + // Return the address of the validator + Addr() types.Address + // Return of copy of the validator + Copy() Validator + // Check the same validator or not + Equal(Validator) bool + // RLP Marshaller to encode to bytes + MarshalRLPWith(*fastrlp.Arena) *fastrlp.Value + // RLP Unmarshaller to encode from bytes + UnmarshalRLPFrom(*fastrlp.Parser, *fastrlp.Value) error + // Return bytes in RLP encode + Bytes() []byte + // Decode bytes in RLP encode and map to the fields + SetFromBytes([]byte) error +} + +// Validators defines the interface of the methods validator collection implements +type Validators interface { + // Return the type of the validators + Type() ValidatorType + // Return the size of collection + Len() int + // Check equality of each element + Equal(Validators) bool + // Return of the whole collection + Copy() Validators + // Get validator at specified height + At(uint64) Validator + // Find the index of the validator that has specified address + Index(types.Address) int64 + // Check the validator that has specified address exists in the collection + Includes(types.Address) bool + // Add a validator into collection + Add(Validator) error + // Remove a validator from collection + Del(Validator) error + // Merge 2 collections into one collection + Merge(Validators) error + // RLP Marshaller to encode to bytes + MarshalRLPWith(*fastrlp.Arena) *fastrlp.Value + // Decode bytes in RLP encode and map to the elements + UnmarshalRLPFrom(*fastrlp.Parser, *fastrlp.Value) error +} diff --git a/validators/types_test.go b/validators/types_test.go new file mode 100644 index 0000000000..d9d19525ae --- /dev/null +++ b/validators/types_test.go @@ -0,0 +1,57 @@ +package validators + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseValidatorType(t *testing.T) { + t.Parallel() + + t.Run("ECDSA", func(t *testing.T) { + t.Parallel() + + res, err := ParseValidatorType("ecdsa") + + assert.Equal( + t, + ECDSAValidatorType, + res, + ) + + assert.NoError( + t, + err, + ) + }) + + t.Run("BLS", func(t *testing.T) { + t.Parallel() + + res, err := ParseValidatorType("bls") + + assert.Equal( + t, + BLSValidatorType, + res, + ) + + assert.NoError( + t, + err, + ) + }) + + t.Run("other type", func(t *testing.T) { + t.Parallel() + + _, err := ParseValidatorType("fake") + + assert.Equal( + t, + ErrInvalidValidatorType, + err, + ) + }) +} diff --git a/vendor/filippo.io/edwards25519/LICENSE b/vendor/filippo.io/edwards25519/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/filippo.io/edwards25519/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/filippo.io/edwards25519/README.md b/vendor/filippo.io/edwards25519/README.md new file mode 100644 index 0000000000..e87d1654cd --- /dev/null +++ b/vendor/filippo.io/edwards25519/README.md @@ -0,0 +1,14 @@ +# filippo.io/edwards25519 + +``` +import "filippo.io/edwards25519" +``` + +This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives. +Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519). + +The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255. + +Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative. + +Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements. diff --git a/vendor/filippo.io/edwards25519/doc.go b/vendor/filippo.io/edwards25519/doc.go new file mode 100644 index 0000000000..d8608b0673 --- /dev/null +++ b/vendor/filippo.io/edwards25519/doc.go @@ -0,0 +1,20 @@ +// Copyright (c) 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package edwards25519 implements group logic for the twisted Edwards curve +// +// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2 +// +// This is better known as the Edwards curve equivalent to Curve25519, and is +// the curve used by the Ed25519 signature scheme. +// +// Most users don't need this package, and should instead use crypto/ed25519 for +// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or +// github.com/gtank/ristretto255 for prime order group logic. +// +// However, developers who do need to interact with low-level edwards25519 +// operations can use this package, which is an extended version of +// crypto/ed25519/internal/edwards25519 from the standard library repackaged as +// an importable module. +package edwards25519 diff --git a/vendor/filippo.io/edwards25519/edwards25519.go b/vendor/filippo.io/edwards25519/edwards25519.go new file mode 100644 index 0000000000..e22a7c2db3 --- /dev/null +++ b/vendor/filippo.io/edwards25519/edwards25519.go @@ -0,0 +1,428 @@ +// Copyright (c) 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +import ( + "errors" + + "filippo.io/edwards25519/field" +) + +// Point types. + +type projP1xP1 struct { + X, Y, Z, T field.Element +} + +type projP2 struct { + X, Y, Z field.Element +} + +// Point represents a point on the edwards25519 curve. +// +// This type works similarly to math/big.Int, and all arguments and receivers +// are allowed to alias. +// +// The zero value is NOT valid, and it may be used only as a receiver. +type Point struct { + // The point is internally represented in extended coordinates (X, Y, Z, T) + // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522. + x, y, z, t field.Element + + // Make the type not comparable (i.e. used with == or as a map key), as + // equivalent points can be represented by different Go values. + _ incomparable +} + +type incomparable [0]func() + +func checkInitialized(points ...*Point) { + for _, p := range points { + if p.x == (field.Element{}) && p.y == (field.Element{}) { + panic("edwards25519: use of uninitialized Point") + } + } +} + +type projCached struct { + YplusX, YminusX, Z, T2d field.Element +} + +type affineCached struct { + YplusX, YminusX, T2d field.Element +} + +// Constructors. + +func (v *projP2) Zero() *projP2 { + v.X.Zero() + v.Y.One() + v.Z.One() + return v +} + +// identity is the point at infinity. +var identity, _ = new(Point).SetBytes([]byte{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + +// NewIdentityPoint returns a new Point set to the identity. +func NewIdentityPoint() *Point { + return new(Point).Set(identity) +} + +// generator is the canonical curve basepoint. See TestGenerator for the +// correspondence of this encoding with the values in RFC 8032. +var generator, _ = new(Point).SetBytes([]byte{ + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}) + +// NewGeneratorPoint returns a new Point set to the canonical generator. +func NewGeneratorPoint() *Point { + return new(Point).Set(generator) +} + +func (v *projCached) Zero() *projCached { + v.YplusX.One() + v.YminusX.One() + v.Z.One() + v.T2d.Zero() + return v +} + +func (v *affineCached) Zero() *affineCached { + v.YplusX.One() + v.YminusX.One() + v.T2d.Zero() + return v +} + +// Assignments. + +// Set sets v = u, and returns v. +func (v *Point) Set(u *Point) *Point { + *v = *u + return v +} + +// Encoding. + +// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032, +// Section 5.1.2. +func (v *Point) Bytes() []byte { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var buf [32]byte + return v.bytes(&buf) +} + +func (v *Point) bytes(buf *[32]byte) []byte { + checkInitialized(v) + + var zInv, x, y field.Element + zInv.Invert(&v.z) // zInv = 1 / Z + x.Multiply(&v.x, &zInv) // x = X / Z + y.Multiply(&v.y, &zInv) // y = Y / Z + + out := copyFieldElement(buf, &y) + out[31] |= byte(x.IsNegative() << 7) + return out +} + +var feOne = new(field.Element).One() + +// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not +// represent a valid point on the curve, SetBytes returns nil and an error and +// the receiver is unchanged. Otherwise, SetBytes returns v. +// +// Note that SetBytes accepts all non-canonical encodings of valid points. +// That is, it follows decoding rules that match most implementations in +// the ecosystem rather than RFC 8032. +func (v *Point) SetBytes(x []byte) (*Point, error) { + // Specifically, the non-canonical encodings that are accepted are + // 1) the ones where the field element is not reduced (see the + // (*field.Element).SetBytes docs) and + // 2) the ones where the x-coordinate is zero and the sign bit is set. + // + // This is consistent with crypto/ed25519/internal/edwards25519. Read more + // at https://hdevalence.ca/blog/2020-10-04-its-25519am, specifically the + // "Canonical A, R" section. + + y, err := new(field.Element).SetBytes(x) + if err != nil { + return nil, errors.New("edwards25519: invalid point encoding length") + } + + // -x² + y² = 1 + dx²y² + // x² + dx²y² = x²(dy² + 1) = y² - 1 + // x² = (y² - 1) / (dy² + 1) + + // u = y² - 1 + y2 := new(field.Element).Square(y) + u := new(field.Element).Subtract(y2, feOne) + + // v = dy² + 1 + vv := new(field.Element).Multiply(y2, d) + vv = vv.Add(vv, feOne) + + // x = +√(u/v) + xx, wasSquare := new(field.Element).SqrtRatio(u, vv) + if wasSquare == 0 { + return nil, errors.New("edwards25519: invalid point encoding") + } + + // Select the negative square root if the sign bit is set. + xxNeg := new(field.Element).Negate(xx) + xx = xx.Select(xxNeg, xx, int(x[31]>>7)) + + v.x.Set(xx) + v.y.Set(y) + v.z.One() + v.t.Multiply(xx, y) // xy = T / Z + + return v, nil +} + +func copyFieldElement(buf *[32]byte, v *field.Element) []byte { + copy(buf[:], v.Bytes()) + return buf[:] +} + +// Conversions. + +func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 { + v.X.Multiply(&p.X, &p.T) + v.Y.Multiply(&p.Y, &p.Z) + v.Z.Multiply(&p.Z, &p.T) + return v +} + +func (v *projP2) FromP3(p *Point) *projP2 { + v.X.Set(&p.x) + v.Y.Set(&p.y) + v.Z.Set(&p.z) + return v +} + +func (v *Point) fromP1xP1(p *projP1xP1) *Point { + v.x.Multiply(&p.X, &p.T) + v.y.Multiply(&p.Y, &p.Z) + v.z.Multiply(&p.Z, &p.T) + v.t.Multiply(&p.X, &p.Y) + return v +} + +func (v *Point) fromP2(p *projP2) *Point { + v.x.Multiply(&p.X, &p.Z) + v.y.Multiply(&p.Y, &p.Z) + v.z.Square(&p.Z) + v.t.Multiply(&p.X, &p.Y) + return v +} + +// d is a constant in the curve equation. +var d, _ = new(field.Element).SetBytes([]byte{ + 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, + 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, + 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, + 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52}) +var d2 = new(field.Element).Add(d, d) + +func (v *projCached) FromP3(p *Point) *projCached { + v.YplusX.Add(&p.y, &p.x) + v.YminusX.Subtract(&p.y, &p.x) + v.Z.Set(&p.z) + v.T2d.Multiply(&p.t, d2) + return v +} + +func (v *affineCached) FromP3(p *Point) *affineCached { + v.YplusX.Add(&p.y, &p.x) + v.YminusX.Subtract(&p.y, &p.x) + v.T2d.Multiply(&p.t, d2) + + var invZ field.Element + invZ.Invert(&p.z) + v.YplusX.Multiply(&v.YplusX, &invZ) + v.YminusX.Multiply(&v.YminusX, &invZ) + v.T2d.Multiply(&v.T2d, &invZ) + return v +} + +// (Re)addition and subtraction. + +// Add sets v = p + q, and returns v. +func (v *Point) Add(p, q *Point) *Point { + checkInitialized(p, q) + qCached := new(projCached).FromP3(q) + result := new(projP1xP1).Add(p, qCached) + return v.fromP1xP1(result) +} + +// Subtract sets v = p - q, and returns v. +func (v *Point) Subtract(p, q *Point) *Point { + checkInitialized(p, q) + qCached := new(projCached).FromP3(q) + result := new(projP1xP1).Sub(p, qCached) + return v.fromP1xP1(result) +} + +func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 { + var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element + + YplusX.Add(&p.y, &p.x) + YminusX.Subtract(&p.y, &p.x) + + PP.Multiply(&YplusX, &q.YplusX) + MM.Multiply(&YminusX, &q.YminusX) + TT2d.Multiply(&p.t, &q.T2d) + ZZ2.Multiply(&p.z, &q.Z) + + ZZ2.Add(&ZZ2, &ZZ2) + + v.X.Subtract(&PP, &MM) + v.Y.Add(&PP, &MM) + v.Z.Add(&ZZ2, &TT2d) + v.T.Subtract(&ZZ2, &TT2d) + return v +} + +func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 { + var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element + + YplusX.Add(&p.y, &p.x) + YminusX.Subtract(&p.y, &p.x) + + PP.Multiply(&YplusX, &q.YminusX) // flipped sign + MM.Multiply(&YminusX, &q.YplusX) // flipped sign + TT2d.Multiply(&p.t, &q.T2d) + ZZ2.Multiply(&p.z, &q.Z) + + ZZ2.Add(&ZZ2, &ZZ2) + + v.X.Subtract(&PP, &MM) + v.Y.Add(&PP, &MM) + v.Z.Subtract(&ZZ2, &TT2d) // flipped sign + v.T.Add(&ZZ2, &TT2d) // flipped sign + return v +} + +func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 { + var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element + + YplusX.Add(&p.y, &p.x) + YminusX.Subtract(&p.y, &p.x) + + PP.Multiply(&YplusX, &q.YplusX) + MM.Multiply(&YminusX, &q.YminusX) + TT2d.Multiply(&p.t, &q.T2d) + + Z2.Add(&p.z, &p.z) + + v.X.Subtract(&PP, &MM) + v.Y.Add(&PP, &MM) + v.Z.Add(&Z2, &TT2d) + v.T.Subtract(&Z2, &TT2d) + return v +} + +func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 { + var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element + + YplusX.Add(&p.y, &p.x) + YminusX.Subtract(&p.y, &p.x) + + PP.Multiply(&YplusX, &q.YminusX) // flipped sign + MM.Multiply(&YminusX, &q.YplusX) // flipped sign + TT2d.Multiply(&p.t, &q.T2d) + + Z2.Add(&p.z, &p.z) + + v.X.Subtract(&PP, &MM) + v.Y.Add(&PP, &MM) + v.Z.Subtract(&Z2, &TT2d) // flipped sign + v.T.Add(&Z2, &TT2d) // flipped sign + return v +} + +// Doubling. + +func (v *projP1xP1) Double(p *projP2) *projP1xP1 { + var XX, YY, ZZ2, XplusYsq field.Element + + XX.Square(&p.X) + YY.Square(&p.Y) + ZZ2.Square(&p.Z) + ZZ2.Add(&ZZ2, &ZZ2) + XplusYsq.Add(&p.X, &p.Y) + XplusYsq.Square(&XplusYsq) + + v.Y.Add(&YY, &XX) + v.Z.Subtract(&YY, &XX) + + v.X.Subtract(&XplusYsq, &v.Y) + v.T.Subtract(&ZZ2, &v.Z) + return v +} + +// Negation. + +// Negate sets v = -p, and returns v. +func (v *Point) Negate(p *Point) *Point { + checkInitialized(p) + v.x.Negate(&p.x) + v.y.Set(&p.y) + v.z.Set(&p.z) + v.t.Negate(&p.t) + return v +} + +// Equal returns 1 if v is equivalent to u, and 0 otherwise. +func (v *Point) Equal(u *Point) int { + checkInitialized(v, u) + + var t1, t2, t3, t4 field.Element + t1.Multiply(&v.x, &u.z) + t2.Multiply(&u.x, &v.z) + t3.Multiply(&v.y, &u.z) + t4.Multiply(&u.y, &v.z) + + return t1.Equal(&t2) & t3.Equal(&t4) +} + +// Constant-time operations + +// Select sets v to a if cond == 1 and to b if cond == 0. +func (v *projCached) Select(a, b *projCached, cond int) *projCached { + v.YplusX.Select(&a.YplusX, &b.YplusX, cond) + v.YminusX.Select(&a.YminusX, &b.YminusX, cond) + v.Z.Select(&a.Z, &b.Z, cond) + v.T2d.Select(&a.T2d, &b.T2d, cond) + return v +} + +// Select sets v to a if cond == 1 and to b if cond == 0. +func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached { + v.YplusX.Select(&a.YplusX, &b.YplusX, cond) + v.YminusX.Select(&a.YminusX, &b.YminusX, cond) + v.T2d.Select(&a.T2d, &b.T2d, cond) + return v +} + +// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. +func (v *projCached) CondNeg(cond int) *projCached { + v.YplusX.Swap(&v.YminusX, cond) + v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) + return v +} + +// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. +func (v *affineCached) CondNeg(cond int) *affineCached { + v.YplusX.Swap(&v.YminusX, cond) + v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) + return v +} diff --git a/vendor/filippo.io/edwards25519/extra.go b/vendor/filippo.io/edwards25519/extra.go new file mode 100644 index 0000000000..f5e5908037 --- /dev/null +++ b/vendor/filippo.io/edwards25519/extra.go @@ -0,0 +1,343 @@ +// Copyright (c) 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +// This file contains additional functionality that is not included in the +// upstream crypto/ed25519/internal/edwards25519 package. + +import ( + "errors" + + "filippo.io/edwards25519/field" +) + +// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where +// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. +func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. Don't change the style without making + // sure it doesn't increase the inliner cost. + var e [4]field.Element + X, Y, Z, T = v.extendedCoordinates(&e) + return +} + +func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) { + checkInitialized(v) + X = e[0].Set(&v.x) + Y = e[1].Set(&v.y) + Z = e[2].Set(&v.z) + T = e[3].Set(&v.t) + return +} + +// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where +// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522. +// +// If the coordinates are invalid or don't represent a valid point on the curve, +// SetExtendedCoordinates returns nil and an error and the receiver is +// unchanged. Otherwise, SetExtendedCoordinates returns v. +func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) { + if !isOnCurve(X, Y, Z, T) { + return nil, errors.New("edwards25519: invalid point coordinates") + } + v.x.Set(X) + v.y.Set(Y) + v.z.Set(Z) + v.t.Set(T) + return v, nil +} + +func isOnCurve(X, Y, Z, T *field.Element) bool { + var lhs, rhs field.Element + XX := new(field.Element).Square(X) + YY := new(field.Element).Square(Y) + ZZ := new(field.Element).Square(Z) + TT := new(field.Element).Square(T) + // -x² + y² = 1 + dx²y² + // -(X/Z)² + (Y/Z)² = 1 + d(T/Z)² + // -X² + Y² = Z² + dT² + lhs.Subtract(YY, XX) + rhs.Multiply(d, TT).Add(&rhs, ZZ) + if lhs.Equal(&rhs) != 1 { + return false + } + // xy = T/Z + // XY/Z² = T/Z + // XY = TZ + lhs.Multiply(X, Y) + rhs.Multiply(T, Z) + return lhs.Equal(&rhs) == 1 +} + +// BytesMontgomery converts v to a point on the birationally-equivalent +// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding +// according to RFC 7748. +// +// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode +// to the same value. If v is the identity point, BytesMontgomery returns 32 +// zero bytes, analogously to the X25519 function. +func (v *Point) BytesMontgomery() []byte { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var buf [32]byte + return v.bytesMontgomery(&buf) +} + +func (v *Point) bytesMontgomery(buf *[32]byte) []byte { + checkInitialized(v) + + // RFC 7748, Section 4.1 provides the bilinear map to calculate the + // Montgomery u-coordinate + // + // u = (1 + y) / (1 - y) + // + // where y = Y / Z. + + var y, recip, u field.Element + + y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z + recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y) + u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r + + return copyFieldElement(buf, &u) +} + +// MultByCofactor sets v = 8 * p, and returns v. +func (v *Point) MultByCofactor(p *Point) *Point { + checkInitialized(p) + result := projP1xP1{} + pp := (&projP2{}).FromP3(p) + result.Double(pp) + pp.FromP1xP1(&result) + result.Double(pp) + pp.FromP1xP1(&result) + result.Double(pp) + return v.fromP1xP1(&result) +} + +// Given k > 0, set s = s**(2*i). +func (s *Scalar) pow2k(k int) { + for i := 0; i < k; i++ { + s.Multiply(s, s) + } +} + +// Invert sets s to the inverse of a nonzero scalar v, and returns s. +// +// If t is zero, Invert returns zero. +func (s *Scalar) Invert(t *Scalar) *Scalar { + // Uses a hardcoded sliding window of width 4. + var table [8]Scalar + var tt Scalar + tt.Multiply(t, t) + table[0] = *t + for i := 0; i < 7; i++ { + table[i+1].Multiply(&table[i], &tt) + } + // Now table = [t**1, t**3, t**7, t**11, t**13, t**15] + // so t**k = t[k/2] for odd k + + // To compute the sliding window digits, use the following Sage script: + + // sage: import itertools + // sage: def sliding_window(w,k): + // ....: digits = [] + // ....: while k > 0: + // ....: if k % 2 == 1: + // ....: kmod = k % (2**w) + // ....: digits.append(kmod) + // ....: k = k - kmod + // ....: else: + // ....: digits.append(0) + // ....: k = k // 2 + // ....: return digits + + // Now we can compute s roughly as follows: + + // sage: s = 1 + // sage: for coeff in reversed(sliding_window(4,l-2)): + // ....: s = s*s + // ....: if coeff > 0 : + // ....: s = s*t**coeff + + // This works on one bit at a time, with many runs of zeros. + // The digits can be collapsed into [(count, coeff)] as follows: + + // sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))] + + // Entries of the form (k, 0) turn into pow2k(k) + // Entries of the form (1, coeff) turn into a squaring and then a table lookup. + // We can fold the squaring into the previous pow2k(k) as pow2k(k+1). + + *s = table[1/2] + s.pow2k(127 + 1) + s.Multiply(s, &table[1/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[9/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[11/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[13/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[15/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[7/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[15/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[5/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[1/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[15/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[15/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[7/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[3/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[11/2]) + s.pow2k(5 + 1) + s.Multiply(s, &table[11/2]) + s.pow2k(9 + 1) + s.Multiply(s, &table[9/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[3/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[3/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[3/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[9/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[7/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[3/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[13/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[7/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[9/2]) + s.pow2k(3 + 1) + s.Multiply(s, &table[15/2]) + s.pow2k(4 + 1) + s.Multiply(s, &table[11/2]) + + return s +} + +// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. +// +// Execution time depends only on the lengths of the two slices, which must match. +func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point { + if len(scalars) != len(points) { + panic("edwards25519: called MultiScalarMult with different size inputs") + } + checkInitialized(points...) + + // Proceed as in the single-base case, but share doublings + // between each point in the multiscalar equation. + + // Build lookup tables for each point + tables := make([]projLookupTable, len(points)) + for i := range tables { + tables[i].FromP3(points[i]) + } + // Compute signed radix-16 digits for each scalar + digits := make([][64]int8, len(scalars)) + for i := range digits { + digits[i] = scalars[i].signedRadix16() + } + + // Unwrap first loop iteration to save computing 16*identity + multiple := &projCached{} + tmp1 := &projP1xP1{} + tmp2 := &projP2{} + // Lookup-and-add the appropriate multiple of each input point + for j := range tables { + tables[j].SelectInto(multiple, digits[j][63]) + tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords + v.fromP1xP1(tmp1) // update v + } + tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration + for i := 62; i >= 0; i-- { + tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords + v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords + // Lookup-and-add the appropriate multiple of each input point + for j := range tables { + tables[j].SelectInto(multiple, digits[j][i]) + tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords + v.fromP1xP1(tmp1) // update v + } + tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration + } + return v +} + +// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v. +// +// Execution time depends on the inputs. +func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point { + if len(scalars) != len(points) { + panic("edwards25519: called VarTimeMultiScalarMult with different size inputs") + } + checkInitialized(points...) + + // Generalize double-base NAF computation to arbitrary sizes. + // Here all the points are dynamic, so we only use the smaller + // tables. + + // Build lookup tables for each point + tables := make([]nafLookupTable5, len(points)) + for i := range tables { + tables[i].FromP3(points[i]) + } + // Compute a NAF for each scalar + nafs := make([][256]int8, len(scalars)) + for i := range nafs { + nafs[i] = scalars[i].nonAdjacentForm(5) + } + + multiple := &projCached{} + tmp1 := &projP1xP1{} + tmp2 := &projP2{} + tmp2.Zero() + + // Move from high to low bits, doubling the accumulator + // at each iteration and checking whether there is a nonzero + // coefficient to look up a multiple of. + // + // Skip trying to find the first nonzero coefficent, because + // searching might be more work than a few extra doublings. + for i := 255; i >= 0; i-- { + tmp1.Double(tmp2) + + for j := range nafs { + if nafs[j][i] > 0 { + v.fromP1xP1(tmp1) + tables[j].SelectInto(multiple, nafs[j][i]) + tmp1.Add(v, multiple) + } else if nafs[j][i] < 0 { + v.fromP1xP1(tmp1) + tables[j].SelectInto(multiple, -nafs[j][i]) + tmp1.Sub(v, multiple) + } + } + + tmp2.FromP1xP1(tmp1) + } + + v.fromP2(tmp2) + return v +} diff --git a/vendor/filippo.io/edwards25519/field/fe.go b/vendor/filippo.io/edwards25519/field/fe.go new file mode 100644 index 0000000000..e5f5385939 --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe.go @@ -0,0 +1,419 @@ +// Copyright (c) 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package field implements fast arithmetic modulo 2^255-19. +package field + +import ( + "crypto/subtle" + "encoding/binary" + "errors" + "math/bits" +) + +// Element represents an element of the field GF(2^255-19). Note that this +// is not a cryptographically secure group, and should only be used to interact +// with edwards25519.Point coordinates. +// +// This type works similarly to math/big.Int, and all arguments and receivers +// are allowed to alias. +// +// The zero value is a valid zero element. +type Element struct { + // An element t represents the integer + // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204 + // + // Between operations, all limbs are expected to be lower than 2^52. + l0 uint64 + l1 uint64 + l2 uint64 + l3 uint64 + l4 uint64 +} + +const maskLow51Bits uint64 = (1 << 51) - 1 + +var feZero = &Element{0, 0, 0, 0, 0} + +// Zero sets v = 0, and returns v. +func (v *Element) Zero() *Element { + *v = *feZero + return v +} + +var feOne = &Element{1, 0, 0, 0, 0} + +// One sets v = 1, and returns v. +func (v *Element) One() *Element { + *v = *feOne + return v +} + +// reduce reduces v modulo 2^255 - 19 and returns it. +func (v *Element) reduce() *Element { + v.carryPropagate() + + // After the light reduction we now have a field element representation + // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19. + + // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1, + // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise. + c := (v.l0 + 19) >> 51 + c = (v.l1 + c) >> 51 + c = (v.l2 + c) >> 51 + c = (v.l3 + c) >> 51 + c = (v.l4 + c) >> 51 + + // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's + // effectively applying the reduction identity to the carry. + v.l0 += 19 * c + + v.l1 += v.l0 >> 51 + v.l0 = v.l0 & maskLow51Bits + v.l2 += v.l1 >> 51 + v.l1 = v.l1 & maskLow51Bits + v.l3 += v.l2 >> 51 + v.l2 = v.l2 & maskLow51Bits + v.l4 += v.l3 >> 51 + v.l3 = v.l3 & maskLow51Bits + // no additional carry + v.l4 = v.l4 & maskLow51Bits + + return v +} + +// Add sets v = a + b, and returns v. +func (v *Element) Add(a, b *Element) *Element { + v.l0 = a.l0 + b.l0 + v.l1 = a.l1 + b.l1 + v.l2 = a.l2 + b.l2 + v.l3 = a.l3 + b.l3 + v.l4 = a.l4 + b.l4 + // Using the generic implementation here is actually faster than the + // assembly. Probably because the body of this function is so simple that + // the compiler can figure out better optimizations by inlining the carry + // propagation. + return v.carryPropagateGeneric() +} + +// Subtract sets v = a - b, and returns v. +func (v *Element) Subtract(a, b *Element) *Element { + // We first add 2 * p, to guarantee the subtraction won't underflow, and + // then subtract b (which can be up to 2^255 + 2^13 * 19). + v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0 + v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1 + v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2 + v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3 + v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4 + return v.carryPropagate() +} + +// Negate sets v = -a, and returns v. +func (v *Element) Negate(a *Element) *Element { + return v.Subtract(feZero, a) +} + +// Invert sets v = 1/z mod p, and returns v. +// +// If z == 0, Invert returns v = 0. +func (v *Element) Invert(z *Element) *Element { + // Inversion is implemented as exponentiation with exponent p − 2. It uses the + // same sequence of 255 squarings and 11 multiplications as [Curve25519]. + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element + + z2.Square(z) // 2 + t.Square(&z2) // 4 + t.Square(&t) // 8 + z9.Multiply(&t, z) // 9 + z11.Multiply(&z9, &z2) // 11 + t.Square(&z11) // 22 + z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0 + + t.Square(&z2_5_0) // 2^6 - 2^1 + for i := 0; i < 4; i++ { + t.Square(&t) // 2^10 - 2^5 + } + z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0 + + t.Square(&z2_10_0) // 2^11 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^20 - 2^10 + } + z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0 + + t.Square(&z2_20_0) // 2^21 - 2^1 + for i := 0; i < 19; i++ { + t.Square(&t) // 2^40 - 2^20 + } + t.Multiply(&t, &z2_20_0) // 2^40 - 2^0 + + t.Square(&t) // 2^41 - 2^1 + for i := 0; i < 9; i++ { + t.Square(&t) // 2^50 - 2^10 + } + z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0 + + t.Square(&z2_50_0) // 2^51 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^100 - 2^50 + } + z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0 + + t.Square(&z2_100_0) // 2^101 - 2^1 + for i := 0; i < 99; i++ { + t.Square(&t) // 2^200 - 2^100 + } + t.Multiply(&t, &z2_100_0) // 2^200 - 2^0 + + t.Square(&t) // 2^201 - 2^1 + for i := 0; i < 49; i++ { + t.Square(&t) // 2^250 - 2^50 + } + t.Multiply(&t, &z2_50_0) // 2^250 - 2^0 + + t.Square(&t) // 2^251 - 2^1 + t.Square(&t) // 2^252 - 2^2 + t.Square(&t) // 2^253 - 2^3 + t.Square(&t) // 2^254 - 2^4 + t.Square(&t) // 2^255 - 2^5 + + return v.Multiply(&t, &z11) // 2^255 - 21 +} + +// Set sets v = a, and returns v. +func (v *Element) Set(a *Element) *Element { + *v = *a + return v +} + +// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is +// not of the right length, SetUniformBytes returns nil and an error, and the +// receiver is unchanged. +// +// Consistent with RFC 7748, the most significant bit (the high bit of the +// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1) +// are accepted. Note that this is laxer than specified by RFC 8032. +func (v *Element) SetBytes(x []byte) (*Element, error) { + if len(x) != 32 { + return nil, errors.New("edwards25519: invalid field element input size") + } + + // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). + v.l0 = binary.LittleEndian.Uint64(x[0:8]) + v.l0 &= maskLow51Bits + // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). + v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 + v.l1 &= maskLow51Bits + // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). + v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 + v.l2 &= maskLow51Bits + // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). + v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 + v.l3 &= maskLow51Bits + // Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51). + // Note: not bytes 25:33, shift 4, to avoid overread. + v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 + v.l4 &= maskLow51Bits + + return v, nil +} + +// Bytes returns the canonical 32-byte little-endian encoding of v. +func (v *Element) Bytes() []byte { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var out [32]byte + return v.bytes(&out) +} + +func (v *Element) bytes(out *[32]byte) []byte { + t := *v + t.reduce() + + var buf [8]byte + for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { + bitsOffset := i * 51 + binary.LittleEndian.PutUint64(buf[:], l<= len(out) { + break + } + out[off] |= bb + } + } + + return out[:] +} + +// Equal returns 1 if v and u are equal, and 0 otherwise. +func (v *Element) Equal(u *Element) int { + sa, sv := u.Bytes(), v.Bytes() + return subtle.ConstantTimeCompare(sa, sv) +} + +// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise. +func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) } + +// Select sets v to a if cond == 1, and to b if cond == 0. +func (v *Element) Select(a, b *Element, cond int) *Element { + m := mask64Bits(cond) + v.l0 = (m & a.l0) | (^m & b.l0) + v.l1 = (m & a.l1) | (^m & b.l1) + v.l2 = (m & a.l2) | (^m & b.l2) + v.l3 = (m & a.l3) | (^m & b.l3) + v.l4 = (m & a.l4) | (^m & b.l4) + return v +} + +// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v. +func (v *Element) Swap(u *Element, cond int) { + m := mask64Bits(cond) + t := m & (v.l0 ^ u.l0) + v.l0 ^= t + u.l0 ^= t + t = m & (v.l1 ^ u.l1) + v.l1 ^= t + u.l1 ^= t + t = m & (v.l2 ^ u.l2) + v.l2 ^= t + u.l2 ^= t + t = m & (v.l3 ^ u.l3) + v.l3 ^= t + u.l3 ^= t + t = m & (v.l4 ^ u.l4) + v.l4 ^= t + u.l4 ^= t +} + +// IsNegative returns 1 if v is negative, and 0 otherwise. +func (v *Element) IsNegative() int { + return int(v.Bytes()[0] & 1) +} + +// Absolute sets v to |u|, and returns v. +func (v *Element) Absolute(u *Element) *Element { + return v.Select(new(Element).Negate(u), u, u.IsNegative()) +} + +// Multiply sets v = x * y, and returns v. +func (v *Element) Multiply(x, y *Element) *Element { + feMul(v, x, y) + return v +} + +// Square sets v = x * x, and returns v. +func (v *Element) Square(x *Element) *Element { + feSquare(v, x) + return v +} + +// Mult32 sets v = x * y, and returns v. +func (v *Element) Mult32(x *Element, y uint32) *Element { + x0lo, x0hi := mul51(x.l0, y) + x1lo, x1hi := mul51(x.l1, y) + x2lo, x2hi := mul51(x.l2, y) + x3lo, x3hi := mul51(x.l3, y) + x4lo, x4hi := mul51(x.l4, y) + v.l0 = x0lo + 19*x4hi // carried over per the reduction identity + v.l1 = x1lo + x0hi + v.l2 = x2lo + x1hi + v.l3 = x3lo + x2hi + v.l4 = x4lo + x3hi + // The hi portions are going to be only 32 bits, plus any previous excess, + // so we can skip the carry propagation. + return v +} + +// mul51 returns lo + hi * 2⁵¹ = a * b. +func mul51(a uint64, b uint32) (lo uint64, hi uint64) { + mh, ml := bits.Mul64(a, uint64(b)) + lo = ml & maskLow51Bits + hi = (mh << 13) | (ml >> 51) + return +} + +// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3. +func (v *Element) Pow22523(x *Element) *Element { + var t0, t1, t2 Element + + t0.Square(x) // x^2 + t1.Square(&t0) // x^4 + t1.Square(&t1) // x^8 + t1.Multiply(x, &t1) // x^9 + t0.Multiply(&t0, &t1) // x^11 + t0.Square(&t0) // x^22 + t0.Multiply(&t1, &t0) // x^31 + t1.Square(&t0) // x^62 + for i := 1; i < 5; i++ { // x^992 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1 + t1.Square(&t0) // 2^11 - 2 + for i := 1; i < 10; i++ { // 2^20 - 2^10 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^20 - 1 + t2.Square(&t1) // 2^21 - 2 + for i := 1; i < 20; i++ { // 2^40 - 2^20 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^40 - 1 + t1.Square(&t1) // 2^41 - 2 + for i := 1; i < 10; i++ { // 2^50 - 2^10 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^50 - 1 + t1.Square(&t0) // 2^51 - 2 + for i := 1; i < 50; i++ { // 2^100 - 2^50 + t1.Square(&t1) + } + t1.Multiply(&t1, &t0) // 2^100 - 1 + t2.Square(&t1) // 2^101 - 2 + for i := 1; i < 100; i++ { // 2^200 - 2^100 + t2.Square(&t2) + } + t1.Multiply(&t2, &t1) // 2^200 - 1 + t1.Square(&t1) // 2^201 - 2 + for i := 1; i < 50; i++ { // 2^250 - 2^50 + t1.Square(&t1) + } + t0.Multiply(&t1, &t0) // 2^250 - 1 + t0.Square(&t0) // 2^251 - 2 + t0.Square(&t0) // 2^252 - 4 + return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3) +} + +// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion. +var sqrtM1 = &Element{1718705420411056, 234908883556509, + 2233514472574048, 2117202627021982, 765476049583133} + +// SqrtRatio sets r to the non-negative square root of the ratio of u and v. +// +// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio +// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, +// and returns r and 0. +func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) { + var a, b Element + + // r = (u * v3) * (u * v7)^((p-5)/8) + v2 := a.Square(v) + uv3 := b.Multiply(u, b.Multiply(v2, v)) + uv7 := a.Multiply(uv3, a.Square(v2)) + r.Multiply(uv3, r.Pow22523(uv7)) + + check := a.Multiply(v, a.Square(r)) // check = v * r^2 + + uNeg := b.Negate(u) + correctSignSqrt := check.Equal(u) + flippedSignSqrt := check.Equal(uNeg) + flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1)) + + rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r + // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) + r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI) + + r.Absolute(r) // Choose the nonnegative square root. + return r, correctSignSqrt | flippedSignSqrt +} diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.go b/vendor/filippo.io/edwards25519/field/fe_amd64.go new file mode 100644 index 0000000000..44dc8e8caf --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_amd64.go @@ -0,0 +1,13 @@ +// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. + +// +build amd64,gc,!purego + +package field + +// feMul sets out = a * b. It works like feMulGeneric. +//go:noescape +func feMul(out *Element, a *Element, b *Element) + +// feSquare sets out = a * a. It works like feSquareGeneric. +//go:noescape +func feSquare(out *Element, a *Element) diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.s b/vendor/filippo.io/edwards25519/field/fe_amd64.s new file mode 100644 index 0000000000..0aa1e86d98 --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_amd64.s @@ -0,0 +1,378 @@ +// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. + +// +build amd64,gc,!purego + +#include "textflag.h" + +// func feMul(out *Element, a *Element, b *Element) +TEXT ·feMul(SB), NOSPLIT, $0-24 + MOVQ a+8(FP), CX + MOVQ b+16(FP), BX + + // r0 = a0×b0 + MOVQ (CX), AX + MULQ (BX) + MOVQ AX, DI + MOVQ DX, SI + + // r0 += 19×a1×b4 + MOVQ 8(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a2×b3 + MOVQ 16(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a3×b2 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 16(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r0 += 19×a4×b1 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 8(BX) + ADDQ AX, DI + ADCQ DX, SI + + // r1 = a0×b1 + MOVQ (CX), AX + MULQ 8(BX) + MOVQ AX, R9 + MOVQ DX, R8 + + // r1 += a1×b0 + MOVQ 8(CX), AX + MULQ (BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a2×b4 + MOVQ 16(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a3×b3 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r1 += 19×a4×b2 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 16(BX) + ADDQ AX, R9 + ADCQ DX, R8 + + // r2 = a0×b2 + MOVQ (CX), AX + MULQ 16(BX) + MOVQ AX, R11 + MOVQ DX, R10 + + // r2 += a1×b1 + MOVQ 8(CX), AX + MULQ 8(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += a2×b0 + MOVQ 16(CX), AX + MULQ (BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += 19×a3×b4 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r2 += 19×a4×b3 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(BX) + ADDQ AX, R11 + ADCQ DX, R10 + + // r3 = a0×b3 + MOVQ (CX), AX + MULQ 24(BX) + MOVQ AX, R13 + MOVQ DX, R12 + + // r3 += a1×b2 + MOVQ 8(CX), AX + MULQ 16(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += a2×b1 + MOVQ 16(CX), AX + MULQ 8(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += a3×b0 + MOVQ 24(CX), AX + MULQ (BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r3 += 19×a4×b4 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(BX) + ADDQ AX, R13 + ADCQ DX, R12 + + // r4 = a0×b4 + MOVQ (CX), AX + MULQ 32(BX) + MOVQ AX, R15 + MOVQ DX, R14 + + // r4 += a1×b3 + MOVQ 8(CX), AX + MULQ 24(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a2×b2 + MOVQ 16(CX), AX + MULQ 16(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a3×b1 + MOVQ 24(CX), AX + MULQ 8(BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // r4 += a4×b0 + MOVQ 32(CX), AX + MULQ (BX) + ADDQ AX, R15 + ADCQ DX, R14 + + // First reduction chain + MOVQ $0x0007ffffffffffff, AX + SHLQ $0x0d, DI, SI + SHLQ $0x0d, R9, R8 + SHLQ $0x0d, R11, R10 + SHLQ $0x0d, R13, R12 + SHLQ $0x0d, R15, R14 + ANDQ AX, DI + IMUL3Q $0x13, R14, R14 + ADDQ R14, DI + ANDQ AX, R9 + ADDQ SI, R9 + ANDQ AX, R11 + ADDQ R8, R11 + ANDQ AX, R13 + ADDQ R10, R13 + ANDQ AX, R15 + ADDQ R12, R15 + + // Second reduction chain (carryPropagate) + MOVQ DI, SI + SHRQ $0x33, SI + MOVQ R9, R8 + SHRQ $0x33, R8 + MOVQ R11, R10 + SHRQ $0x33, R10 + MOVQ R13, R12 + SHRQ $0x33, R12 + MOVQ R15, R14 + SHRQ $0x33, R14 + ANDQ AX, DI + IMUL3Q $0x13, R14, R14 + ADDQ R14, DI + ANDQ AX, R9 + ADDQ SI, R9 + ANDQ AX, R11 + ADDQ R8, R11 + ANDQ AX, R13 + ADDQ R10, R13 + ANDQ AX, R15 + ADDQ R12, R15 + + // Store output + MOVQ out+0(FP), AX + MOVQ DI, (AX) + MOVQ R9, 8(AX) + MOVQ R11, 16(AX) + MOVQ R13, 24(AX) + MOVQ R15, 32(AX) + RET + +// func feSquare(out *Element, a *Element) +TEXT ·feSquare(SB), NOSPLIT, $0-16 + MOVQ a+8(FP), CX + + // r0 = l0×l0 + MOVQ (CX), AX + MULQ (CX) + MOVQ AX, SI + MOVQ DX, BX + + // r0 += 38×l1×l4 + MOVQ 8(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, SI + ADCQ DX, BX + + // r0 += 38×l2×l3 + MOVQ 16(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 24(CX) + ADDQ AX, SI + ADCQ DX, BX + + // r1 = 2×l0×l1 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 8(CX) + MOVQ AX, R8 + MOVQ DX, DI + + // r1 += 38×l2×l4 + MOVQ 16(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, R8 + ADCQ DX, DI + + // r1 += 19×l3×l3 + MOVQ 24(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 24(CX) + ADDQ AX, R8 + ADCQ DX, DI + + // r2 = 2×l0×l2 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 16(CX) + MOVQ AX, R10 + MOVQ DX, R9 + + // r2 += l1×l1 + MOVQ 8(CX), AX + MULQ 8(CX) + ADDQ AX, R10 + ADCQ DX, R9 + + // r2 += 38×l3×l4 + MOVQ 24(CX), AX + IMUL3Q $0x26, AX, AX + MULQ 32(CX) + ADDQ AX, R10 + ADCQ DX, R9 + + // r3 = 2×l0×l3 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 24(CX) + MOVQ AX, R12 + MOVQ DX, R11 + + // r3 += 2×l1×l2 + MOVQ 8(CX), AX + IMUL3Q $0x02, AX, AX + MULQ 16(CX) + ADDQ AX, R12 + ADCQ DX, R11 + + // r3 += 19×l4×l4 + MOVQ 32(CX), AX + IMUL3Q $0x13, AX, AX + MULQ 32(CX) + ADDQ AX, R12 + ADCQ DX, R11 + + // r4 = 2×l0×l4 + MOVQ (CX), AX + SHLQ $0x01, AX + MULQ 32(CX) + MOVQ AX, R14 + MOVQ DX, R13 + + // r4 += 2×l1×l3 + MOVQ 8(CX), AX + IMUL3Q $0x02, AX, AX + MULQ 24(CX) + ADDQ AX, R14 + ADCQ DX, R13 + + // r4 += l2×l2 + MOVQ 16(CX), AX + MULQ 16(CX) + ADDQ AX, R14 + ADCQ DX, R13 + + // First reduction chain + MOVQ $0x0007ffffffffffff, AX + SHLQ $0x0d, SI, BX + SHLQ $0x0d, R8, DI + SHLQ $0x0d, R10, R9 + SHLQ $0x0d, R12, R11 + SHLQ $0x0d, R14, R13 + ANDQ AX, SI + IMUL3Q $0x13, R13, R13 + ADDQ R13, SI + ANDQ AX, R8 + ADDQ BX, R8 + ANDQ AX, R10 + ADDQ DI, R10 + ANDQ AX, R12 + ADDQ R9, R12 + ANDQ AX, R14 + ADDQ R11, R14 + + // Second reduction chain (carryPropagate) + MOVQ SI, BX + SHRQ $0x33, BX + MOVQ R8, DI + SHRQ $0x33, DI + MOVQ R10, R9 + SHRQ $0x33, R9 + MOVQ R12, R11 + SHRQ $0x33, R11 + MOVQ R14, R13 + SHRQ $0x33, R13 + ANDQ AX, SI + IMUL3Q $0x13, R13, R13 + ADDQ R13, SI + ANDQ AX, R8 + ADDQ BX, R8 + ANDQ AX, R10 + ADDQ DI, R10 + ANDQ AX, R12 + ADDQ R9, R12 + ANDQ AX, R14 + ADDQ R11, R14 + + // Store output + MOVQ out+0(FP), AX + MOVQ SI, (AX) + MOVQ R8, 8(AX) + MOVQ R10, 16(AX) + MOVQ R12, 24(AX) + MOVQ R14, 32(AX) + RET diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go new file mode 100644 index 0000000000..ddb6c9b8f7 --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || !gc || purego +// +build !amd64 !gc purego + +package field + +func feMul(v, x, y *Element) { feMulGeneric(v, x, y) } + +func feSquare(v, x *Element) { feSquareGeneric(v, x) } diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.go b/vendor/filippo.io/edwards25519/field/fe_arm64.go new file mode 100644 index 0000000000..af459ef515 --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_arm64.go @@ -0,0 +1,16 @@ +// Copyright (c) 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build arm64 && gc && !purego +// +build arm64,gc,!purego + +package field + +//go:noescape +func carryPropagate(v *Element) + +func (v *Element) carryPropagate() *Element { + carryPropagate(v) + return v +} diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.s b/vendor/filippo.io/edwards25519/field/fe_arm64.s new file mode 100644 index 0000000000..751ab2ada3 --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_arm64.s @@ -0,0 +1,42 @@ +// Copyright (c) 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build arm64,gc,!purego + +#include "textflag.h" + +// carryPropagate works exactly like carryPropagateGeneric and uses the +// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but +// avoids loading R0-R4 twice and uses LDP and STP. +// +// See https://golang.org/issues/43145 for the main compiler issue. +// +// func carryPropagate(v *Element) +TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 + MOVD v+0(FP), R20 + + LDP 0(R20), (R0, R1) + LDP 16(R20), (R2, R3) + MOVD 32(R20), R4 + + AND $0x7ffffffffffff, R0, R10 + AND $0x7ffffffffffff, R1, R11 + AND $0x7ffffffffffff, R2, R12 + AND $0x7ffffffffffff, R3, R13 + AND $0x7ffffffffffff, R4, R14 + + ADD R0>>51, R11, R11 + ADD R1>>51, R12, R12 + ADD R2>>51, R13, R13 + ADD R3>>51, R14, R14 + // R4>>51 * 19 + R10 -> R10 + LSR $51, R4, R21 + MOVD $19, R22 + MADD R22, R10, R21, R10 + + STP (R10, R11), 0(R20) + STP (R12, R13), 16(R20) + MOVD R14, 32(R20) + + RET diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go new file mode 100644 index 0000000000..234a5b2e5d --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go @@ -0,0 +1,12 @@ +// Copyright (c) 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !arm64 || !gc || purego +// +build !arm64 !gc purego + +package field + +func (v *Element) carryPropagate() *Element { + return v.carryPropagateGeneric() +} diff --git a/vendor/filippo.io/edwards25519/field/fe_generic.go b/vendor/filippo.io/edwards25519/field/fe_generic.go new file mode 100644 index 0000000000..bccf8511ac --- /dev/null +++ b/vendor/filippo.io/edwards25519/field/fe_generic.go @@ -0,0 +1,264 @@ +// Copyright (c) 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package field + +import "math/bits" + +// uint128 holds a 128-bit number as two 64-bit limbs, for use with the +// bits.Mul64 and bits.Add64 intrinsics. +type uint128 struct { + lo, hi uint64 +} + +// mul64 returns a * b. +func mul64(a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + return uint128{lo, hi} +} + +// addMul64 returns v + a * b. +func addMul64(v uint128, a, b uint64) uint128 { + hi, lo := bits.Mul64(a, b) + lo, c := bits.Add64(lo, v.lo, 0) + hi, _ = bits.Add64(hi, v.hi, c) + return uint128{lo, hi} +} + +// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. +func shiftRightBy51(a uint128) uint64 { + return (a.hi << (64 - 51)) | (a.lo >> 51) +} + +func feMulGeneric(v, a, b *Element) { + a0 := a.l0 + a1 := a.l1 + a2 := a.l2 + a3 := a.l3 + a4 := a.l4 + + b0 := b.l0 + b1 := b.l1 + b2 := b.l2 + b3 := b.l3 + b4 := b.l4 + + // Limb multiplication works like pen-and-paper columnar multiplication, but + // with 51-bit limbs instead of digits. + // + // a4 a3 a2 a1 a0 x + // b4 b3 b2 b1 b0 = + // ------------------------ + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a4b1 a3b1 a2b1 a1b1 a0b1 + + // a4b2 a3b2 a2b2 a1b2 a0b2 + + // a4b3 a3b3 a2b3 a1b3 a0b3 + + // a4b4 a3b4 a2b4 a1b4 a0b4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to + // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5, + // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc. + // + // Reduction can be carried out simultaneously to multiplication. For + // example, we do not compute r5: whenever the result of a multiplication + // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0. + // + // a4b0 a3b0 a2b0 a1b0 a0b0 + + // a3b1 a2b1 a1b1 a0b1 19×a4b1 + + // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 + + // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 + + // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // Finally we add up the columns into wide, overlapping limbs. + + a1_19 := a1 * 19 + a2_19 := a2 * 19 + a3_19 := a3 * 19 + a4_19 := a4 * 19 + + // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) + r0 := mul64(a0, b0) + r0 = addMul64(r0, a1_19, b4) + r0 = addMul64(r0, a2_19, b3) + r0 = addMul64(r0, a3_19, b2) + r0 = addMul64(r0, a4_19, b1) + + // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) + r1 := mul64(a0, b1) + r1 = addMul64(r1, a1, b0) + r1 = addMul64(r1, a2_19, b4) + r1 = addMul64(r1, a3_19, b3) + r1 = addMul64(r1, a4_19, b2) + + // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) + r2 := mul64(a0, b2) + r2 = addMul64(r2, a1, b1) + r2 = addMul64(r2, a2, b0) + r2 = addMul64(r2, a3_19, b4) + r2 = addMul64(r2, a4_19, b3) + + // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 + r3 := mul64(a0, b3) + r3 = addMul64(r3, a1, b2) + r3 = addMul64(r3, a2, b1) + r3 = addMul64(r3, a3, b0) + r3 = addMul64(r3, a4_19, b4) + + // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 + r4 := mul64(a0, b4) + r4 = addMul64(r4, a1, b3) + r4 = addMul64(r4, a2, b2) + r4 = addMul64(r4, a3, b1) + r4 = addMul64(r4, a4, b0) + + // After the multiplication, we need to reduce (carry) the five coefficients + // to obtain a result with limbs that are at most slightly larger than 2⁵¹, + // to respect the Element invariant. + // + // Overall, the reduction works the same as carryPropagate, except with + // wider inputs: we take the carry for each coefficient by shifting it right + // by 51, and add it to the limb above it. The top carry is multiplied by 19 + // according to the reduction identity and added to the lowest limb. + // + // The largest coefficient (r0) will be at most 111 bits, which guarantees + // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64. + // + // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) + // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²) + // r0 < (1 + 19 × 4) × 2⁵² × 2⁵² + // r0 < 2⁷ × 2⁵² × 2⁵² + // r0 < 2¹¹¹ + // + // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most + // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and + // allows us to easily apply the reduction identity. + // + // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 + // r4 < 5 × 2⁵² × 2⁵² + // r4 < 2¹⁰⁷ + // + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + // Now all coefficients fit into 64-bit registers but are still too large to + // be passed around as a Element. We therefore do one last carry chain, + // where the carries will be small enough to fit in the wiggle room above 2⁵¹. + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +func feSquareGeneric(v, a *Element) { + l0 := a.l0 + l1 := a.l1 + l2 := a.l2 + l3 := a.l3 + l4 := a.l4 + + // Squaring works precisely like multiplication above, but thanks to its + // symmetry we get to group a few terms together. + // + // l4 l3 l2 l1 l0 x + // l4 l3 l2 l1 l0 = + // ------------------------ + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l4l1 l3l1 l2l1 l1l1 l0l1 + + // l4l2 l3l2 l2l2 l1l2 l0l2 + + // l4l3 l3l3 l2l3 l1l3 l0l3 + + // l4l4 l3l4 l2l4 l1l4 l0l4 = + // ---------------------------------------------- + // r8 r7 r6 r5 r4 r3 r2 r1 r0 + // + // l4l0 l3l0 l2l0 l1l0 l0l0 + + // l3l1 l2l1 l1l1 l0l1 19×l4l1 + + // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 + + // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 + + // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = + // -------------------------------------- + // r4 r3 r2 r1 r0 + // + // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with + // only three Mul64 and four Add64, instead of five and eight. + + l0_2 := l0 * 2 + l1_2 := l1 * 2 + + l1_38 := l1 * 38 + l2_38 := l2 * 38 + l3_38 := l3 * 38 + + l3_19 := l3 * 19 + l4_19 := l4 * 19 + + // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) + r0 := mul64(l0, l0) + r0 = addMul64(r0, l1_38, l4) + r0 = addMul64(r0, l2_38, l3) + + // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 + r1 := mul64(l0_2, l1) + r1 = addMul64(r1, l2_38, l4) + r1 = addMul64(r1, l3_19, l3) + + // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 + r2 := mul64(l0_2, l2) + r2 = addMul64(r2, l1, l1) + r2 = addMul64(r2, l3_38, l4) + + // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 + r3 := mul64(l0_2, l3) + r3 = addMul64(r3, l1_2, l2) + r3 = addMul64(r3, l4_19, l4) + + // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 + r4 := mul64(l0_2, l4) + r4 = addMul64(r4, l1_2, l3) + r4 = addMul64(r4, l2, l2) + + c0 := shiftRightBy51(r0) + c1 := shiftRightBy51(r1) + c2 := shiftRightBy51(r2) + c3 := shiftRightBy51(r3) + c4 := shiftRightBy51(r4) + + rr0 := r0.lo&maskLow51Bits + c4*19 + rr1 := r1.lo&maskLow51Bits + c0 + rr2 := r2.lo&maskLow51Bits + c1 + rr3 := r3.lo&maskLow51Bits + c2 + rr4 := r4.lo&maskLow51Bits + c3 + + *v = Element{rr0, rr1, rr2, rr3, rr4} + v.carryPropagate() +} + +// carryPropagate brings the limbs below 52 bits by applying the reduction +// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. +func (v *Element) carryPropagateGeneric() *Element { + c0 := v.l0 >> 51 + c1 := v.l1 >> 51 + c2 := v.l2 >> 51 + c3 := v.l3 >> 51 + c4 := v.l4 >> 51 + + v.l0 = v.l0&maskLow51Bits + c4*19 + v.l1 = v.l1&maskLow51Bits + c0 + v.l2 = v.l2&maskLow51Bits + c1 + v.l3 = v.l3&maskLow51Bits + c2 + v.l4 = v.l4&maskLow51Bits + c3 + + return v +} diff --git a/vendor/filippo.io/edwards25519/scalar.go b/vendor/filippo.io/edwards25519/scalar.go new file mode 100644 index 0000000000..f3da71cebc --- /dev/null +++ b/vendor/filippo.io/edwards25519/scalar.go @@ -0,0 +1,1027 @@ +// Copyright (c) 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +import ( + "crypto/subtle" + "encoding/binary" + "errors" +) + +// A Scalar is an integer modulo +// +// l = 2^252 + 27742317777372353535851937790883648493 +// +// which is the prime order of the edwards25519 group. +// +// This type works similarly to math/big.Int, and all arguments and +// receivers are allowed to alias. +// +// The zero value is a valid zero element. +type Scalar struct { + // s is the Scalar value in little-endian. The value is always reduced + // between operations. + s [32]byte +} + +var ( + scZero = Scalar{[32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + + scOne = Scalar{[32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + + scMinusOne = Scalar{[32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}} +) + +// NewScalar returns a new zero Scalar. +func NewScalar() *Scalar { + return &Scalar{} +} + +// MultiplyAdd sets s = x * y + z mod l, and returns s. +func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar { + scMulAdd(&s.s, &x.s, &y.s, &z.s) + return s +} + +// Add sets s = x + y mod l, and returns s. +func (s *Scalar) Add(x, y *Scalar) *Scalar { + // s = 1 * x + y mod l + scMulAdd(&s.s, &scOne.s, &x.s, &y.s) + return s +} + +// Subtract sets s = x - y mod l, and returns s. +func (s *Scalar) Subtract(x, y *Scalar) *Scalar { + // s = -1 * y + x mod l + scMulAdd(&s.s, &scMinusOne.s, &y.s, &x.s) + return s +} + +// Negate sets s = -x mod l, and returns s. +func (s *Scalar) Negate(x *Scalar) *Scalar { + // s = -1 * x + 0 mod l + scMulAdd(&s.s, &scMinusOne.s, &x.s, &scZero.s) + return s +} + +// Multiply sets s = x * y mod l, and returns s. +func (s *Scalar) Multiply(x, y *Scalar) *Scalar { + // s = x * y + 0 mod l + scMulAdd(&s.s, &x.s, &y.s, &scZero.s) + return s +} + +// Set sets s = x, and returns s. +func (s *Scalar) Set(x *Scalar) *Scalar { + *s = *x + return s +} + +// SetUniformBytes sets s to an uniformly distributed value given 64 uniformly +// distributed random bytes. If x is not of the right length, SetUniformBytes +// returns nil and an error, and the receiver is unchanged. +func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) { + if len(x) != 64 { + return nil, errors.New("edwards25519: invalid SetUniformBytes input length") + } + var wideBytes [64]byte + copy(wideBytes[:], x[:]) + scReduce(&s.s, &wideBytes) + return s, nil +} + +// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of +// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes +// returns nil and an error, and the receiver is unchanged. +func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) { + if len(x) != 32 { + return nil, errors.New("invalid scalar length") + } + ss := &Scalar{} + copy(ss.s[:], x) + if !isReduced(ss) { + return nil, errors.New("invalid scalar encoding") + } + s.s = ss.s + return s, nil +} + +// isReduced returns whether the given scalar is reduced modulo l. +func isReduced(s *Scalar) bool { + for i := len(s.s) - 1; i >= 0; i-- { + switch { + case s.s[i] > scMinusOne.s[i]: + return false + case s.s[i] < scMinusOne.s[i]: + return true + } + } + return true +} + +// SetBytesWithClamping applies the buffer pruning described in RFC 8032, +// Section 5.1.5 (also known as clamping) and sets s to the result. The input +// must be 32 bytes, and it is not modified. If x is not of the right length, +// SetBytesWithClamping returns nil and an error, and the receiver is unchanged. +// +// Note that since Scalar values are always reduced modulo the prime order of +// the curve, the resulting value will not preserve any of the cofactor-clearing +// properties that clamping is meant to provide. It will however work as +// expected as long as it is applied to points on the prime order subgroup, like +// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the +// irrelevant RFC 7748 clamping, but it is now required for compatibility. +func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) { + // The description above omits the purpose of the high bits of the clamping + // for brevity, but those are also lost to reductions, and are also + // irrelevant to edwards25519 as they protect against a specific + // implementation bug that was once observed in a generic Montgomery ladder. + if len(x) != 32 { + return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length") + } + var wideBytes [64]byte + copy(wideBytes[:], x[:]) + wideBytes[0] &= 248 + wideBytes[31] &= 63 + wideBytes[31] |= 64 + scReduce(&s.s, &wideBytes) + return s, nil +} + +// Bytes returns the canonical 32-byte little-endian encoding of s. +func (s *Scalar) Bytes() []byte { + buf := make([]byte, 32) + copy(buf, s.s[:]) + return buf +} + +// Equal returns 1 if s and t are equal, and 0 otherwise. +func (s *Scalar) Equal(t *Scalar) int { + return subtle.ConstantTimeCompare(s.s[:], t.s[:]) +} + +// scMulAdd and scReduce are ported from the public domain, “ref10” +// implementation of ed25519 from SUPERCOP. + +func load3(in []byte) int64 { + r := int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +func load4(in []byte) int64 { + r := int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +// Input: +// a[0]+256*a[1]+...+256^31*a[31] = a +// b[0]+256*b[1]+...+256^31*b[31] = b +// c[0]+256*c[1]+...+256^31*c[31] = c +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func scMulAdd(s, a, b, c *[32]byte) { + a0 := 2097151 & load3(a[:]) + a1 := 2097151 & (load4(a[2:]) >> 5) + a2 := 2097151 & (load3(a[5:]) >> 2) + a3 := 2097151 & (load4(a[7:]) >> 7) + a4 := 2097151 & (load4(a[10:]) >> 4) + a5 := 2097151 & (load3(a[13:]) >> 1) + a6 := 2097151 & (load4(a[15:]) >> 6) + a7 := 2097151 & (load3(a[18:]) >> 3) + a8 := 2097151 & load3(a[21:]) + a9 := 2097151 & (load4(a[23:]) >> 5) + a10 := 2097151 & (load3(a[26:]) >> 2) + a11 := (load4(a[28:]) >> 7) + b0 := 2097151 & load3(b[:]) + b1 := 2097151 & (load4(b[2:]) >> 5) + b2 := 2097151 & (load3(b[5:]) >> 2) + b3 := 2097151 & (load4(b[7:]) >> 7) + b4 := 2097151 & (load4(b[10:]) >> 4) + b5 := 2097151 & (load3(b[13:]) >> 1) + b6 := 2097151 & (load4(b[15:]) >> 6) + b7 := 2097151 & (load3(b[18:]) >> 3) + b8 := 2097151 & load3(b[21:]) + b9 := 2097151 & (load4(b[23:]) >> 5) + b10 := 2097151 & (load3(b[26:]) >> 2) + b11 := (load4(b[28:]) >> 7) + c0 := 2097151 & load3(c[:]) + c1 := 2097151 & (load4(c[2:]) >> 5) + c2 := 2097151 & (load3(c[5:]) >> 2) + c3 := 2097151 & (load4(c[7:]) >> 7) + c4 := 2097151 & (load4(c[10:]) >> 4) + c5 := 2097151 & (load3(c[13:]) >> 1) + c6 := 2097151 & (load4(c[15:]) >> 6) + c7 := 2097151 & (load3(c[18:]) >> 3) + c8 := 2097151 & load3(c[21:]) + c9 := 2097151 & (load4(c[23:]) >> 5) + c10 := 2097151 & (load3(c[26:]) >> 2) + c11 := (load4(c[28:]) >> 7) + var carry [23]int64 + + s0 := c0 + a0*b0 + s1 := c1 + a0*b1 + a1*b0 + s2 := c2 + a0*b2 + a1*b1 + a2*b0 + s3 := c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0 + s4 := c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 + s5 := c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0 + s6 := c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0 + s7 := c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0 + s8 := c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0 + s9 := c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0 + s10 := c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0 + s11 := c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0 + s12 := a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1 + s13 := a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2 + s14 := a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3 + s15 := a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4 + s16 := a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5 + s17 := a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6 + s18 := a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7 + s19 := a8*b11 + a9*b10 + a10*b9 + a11*b8 + s20 := a9*b11 + a10*b10 + a11*b9 + s21 := a10*b11 + a11*b10 + s22 := a11 * b11 + s23 := int64(0) + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + carry[18] = (s18 + (1 << 20)) >> 21 + s19 += carry[18] + s18 -= carry[18] << 21 + carry[20] = (s20 + (1 << 20)) >> 21 + s21 += carry[20] + s20 -= carry[20] << 21 + carry[22] = (s22 + (1 << 20)) >> 21 + s23 += carry[22] + s22 -= carry[22] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + carry[17] = (s17 + (1 << 20)) >> 21 + s18 += carry[17] + s17 -= carry[17] << 21 + carry[19] = (s19 + (1 << 20)) >> 21 + s20 += carry[19] + s19 -= carry[19] << 21 + carry[21] = (s21 + (1 << 20)) >> 21 + s22 += carry[21] + s21 -= carry[21] << 21 + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + s[0] = byte(s0 >> 0) + s[1] = byte(s0 >> 8) + s[2] = byte((s0 >> 16) | (s1 << 5)) + s[3] = byte(s1 >> 3) + s[4] = byte(s1 >> 11) + s[5] = byte((s1 >> 19) | (s2 << 2)) + s[6] = byte(s2 >> 6) + s[7] = byte((s2 >> 14) | (s3 << 7)) + s[8] = byte(s3 >> 1) + s[9] = byte(s3 >> 9) + s[10] = byte((s3 >> 17) | (s4 << 4)) + s[11] = byte(s4 >> 4) + s[12] = byte(s4 >> 12) + s[13] = byte((s4 >> 20) | (s5 << 1)) + s[14] = byte(s5 >> 7) + s[15] = byte((s5 >> 15) | (s6 << 6)) + s[16] = byte(s6 >> 2) + s[17] = byte(s6 >> 10) + s[18] = byte((s6 >> 18) | (s7 << 3)) + s[19] = byte(s7 >> 5) + s[20] = byte(s7 >> 13) + s[21] = byte(s8 >> 0) + s[22] = byte(s8 >> 8) + s[23] = byte((s8 >> 16) | (s9 << 5)) + s[24] = byte(s9 >> 3) + s[25] = byte(s9 >> 11) + s[26] = byte((s9 >> 19) | (s10 << 2)) + s[27] = byte(s10 >> 6) + s[28] = byte((s10 >> 14) | (s11 << 7)) + s[29] = byte(s11 >> 1) + s[30] = byte(s11 >> 9) + s[31] = byte(s11 >> 17) +} + +// Input: +// s[0]+256*s[1]+...+256^63*s[63] = s +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func scReduce(out *[32]byte, s *[64]byte) { + s0 := 2097151 & load3(s[:]) + s1 := 2097151 & (load4(s[2:]) >> 5) + s2 := 2097151 & (load3(s[5:]) >> 2) + s3 := 2097151 & (load4(s[7:]) >> 7) + s4 := 2097151 & (load4(s[10:]) >> 4) + s5 := 2097151 & (load3(s[13:]) >> 1) + s6 := 2097151 & (load4(s[15:]) >> 6) + s7 := 2097151 & (load3(s[18:]) >> 3) + s8 := 2097151 & load3(s[21:]) + s9 := 2097151 & (load4(s[23:]) >> 5) + s10 := 2097151 & (load3(s[26:]) >> 2) + s11 := 2097151 & (load4(s[28:]) >> 7) + s12 := 2097151 & (load4(s[31:]) >> 4) + s13 := 2097151 & (load3(s[34:]) >> 1) + s14 := 2097151 & (load4(s[36:]) >> 6) + s15 := 2097151 & (load3(s[39:]) >> 3) + s16 := 2097151 & load3(s[42:]) + s17 := 2097151 & (load4(s[44:]) >> 5) + s18 := 2097151 & (load3(s[47:]) >> 2) + s19 := 2097151 & (load4(s[49:]) >> 7) + s20 := 2097151 & (load4(s[52:]) >> 4) + s21 := 2097151 & (load3(s[55:]) >> 1) + s22 := 2097151 & (load4(s[57:]) >> 6) + s23 := (load4(s[60:]) >> 3) + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + var carry [17]int64 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + out[0] = byte(s0 >> 0) + out[1] = byte(s0 >> 8) + out[2] = byte((s0 >> 16) | (s1 << 5)) + out[3] = byte(s1 >> 3) + out[4] = byte(s1 >> 11) + out[5] = byte((s1 >> 19) | (s2 << 2)) + out[6] = byte(s2 >> 6) + out[7] = byte((s2 >> 14) | (s3 << 7)) + out[8] = byte(s3 >> 1) + out[9] = byte(s3 >> 9) + out[10] = byte((s3 >> 17) | (s4 << 4)) + out[11] = byte(s4 >> 4) + out[12] = byte(s4 >> 12) + out[13] = byte((s4 >> 20) | (s5 << 1)) + out[14] = byte(s5 >> 7) + out[15] = byte((s5 >> 15) | (s6 << 6)) + out[16] = byte(s6 >> 2) + out[17] = byte(s6 >> 10) + out[18] = byte((s6 >> 18) | (s7 << 3)) + out[19] = byte(s7 >> 5) + out[20] = byte(s7 >> 13) + out[21] = byte(s8 >> 0) + out[22] = byte(s8 >> 8) + out[23] = byte((s8 >> 16) | (s9 << 5)) + out[24] = byte(s9 >> 3) + out[25] = byte(s9 >> 11) + out[26] = byte((s9 >> 19) | (s10 << 2)) + out[27] = byte(s10 >> 6) + out[28] = byte((s10 >> 14) | (s11 << 7)) + out[29] = byte(s11 >> 1) + out[30] = byte(s11 >> 9) + out[31] = byte(s11 >> 17) +} + +// nonAdjacentForm computes a width-w non-adjacent form for this scalar. +// +// w must be between 2 and 8, or nonAdjacentForm will panic. +func (s *Scalar) nonAdjacentForm(w uint) [256]int8 { + // This implementation is adapted from the one + // in curve25519-dalek and is documented there: + // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871 + if s.s[31] > 127 { + panic("scalar has high bit set illegally") + } + if w < 2 { + panic("w must be at least 2 by the definition of NAF") + } else if w > 8 { + panic("NAF digits must fit in int8") + } + + var naf [256]int8 + var digits [5]uint64 + + for i := 0; i < 4; i++ { + digits[i] = binary.LittleEndian.Uint64(s.s[i*8:]) + } + + width := uint64(1 << w) + windowMask := uint64(width - 1) + + pos := uint(0) + carry := uint64(0) + for pos < 256 { + indexU64 := pos / 64 + indexBit := pos % 64 + var bitBuf uint64 + if indexBit < 64-w { + // This window's bits are contained in a single u64 + bitBuf = digits[indexU64] >> indexBit + } else { + // Combine the current 64 bits with bits from the next 64 + bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit)) + } + + // Add carry into the current window + window := carry + (bitBuf & windowMask) + + if window&1 == 0 { + // If the window value is even, preserve the carry and continue. + // Why is the carry preserved? + // If carry == 0 and window & 1 == 0, + // then the next carry should be 0 + // If carry == 1 and window & 1 == 0, + // then bit_buf & 1 == 1 so the next carry should be 1 + pos += 1 + continue + } + + if window < width/2 { + carry = 0 + naf[pos] = int8(window) + } else { + carry = 1 + naf[pos] = int8(window) - int8(width) + } + + pos += w + } + return naf +} + +func (s *Scalar) signedRadix16() [64]int8 { + if s.s[31] > 127 { + panic("scalar has high bit set illegally") + } + + var digits [64]int8 + + // Compute unsigned radix-16 digits: + for i := 0; i < 32; i++ { + digits[2*i] = int8(s.s[i] & 15) + digits[2*i+1] = int8((s.s[i] >> 4) & 15) + } + + // Recenter coefficients: + for i := 0; i < 63; i++ { + carry := (digits[i] + 8) >> 4 + digits[i] -= carry << 4 + digits[i+1] += carry + } + + return digits +} diff --git a/vendor/filippo.io/edwards25519/scalarmult.go b/vendor/filippo.io/edwards25519/scalarmult.go new file mode 100644 index 0000000000..f7ca3cef99 --- /dev/null +++ b/vendor/filippo.io/edwards25519/scalarmult.go @@ -0,0 +1,214 @@ +// Copyright (c) 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +import "sync" + +// basepointTable is a set of 32 affineLookupTables, where table i is generated +// from 256i * basepoint. It is precomputed the first time it's used. +func basepointTable() *[32]affineLookupTable { + basepointTablePrecomp.initOnce.Do(func() { + p := NewGeneratorPoint() + for i := 0; i < 32; i++ { + basepointTablePrecomp.table[i].FromP3(p) + for j := 0; j < 8; j++ { + p.Add(p, p) + } + } + }) + return &basepointTablePrecomp.table +} + +var basepointTablePrecomp struct { + table [32]affineLookupTable + initOnce sync.Once +} + +// ScalarBaseMult sets v = x * B, where B is the canonical generator, and +// returns v. +// +// The scalar multiplication is done in constant time. +func (v *Point) ScalarBaseMult(x *Scalar) *Point { + basepointTable := basepointTable() + + // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i ) + // as described in the Ed25519 paper + // + // Group even and odd coefficients + // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B + // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B + // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B + // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B) + // + // We use a lookup table for each i to get x_i*16^(2*i)*B + // and do four doublings to multiply by 16. + digits := x.signedRadix16() + + multiple := &affineCached{} + tmp1 := &projP1xP1{} + tmp2 := &projP2{} + + // Accumulate the odd components first + v.Set(NewIdentityPoint()) + for i := 1; i < 64; i += 2 { + basepointTable[i/2].SelectInto(multiple, digits[i]) + tmp1.AddAffine(v, multiple) + v.fromP1xP1(tmp1) + } + + // Multiply by 16 + tmp2.FromP3(v) // tmp2 = v in P2 coords + tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords + tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords + tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords + tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords + v.fromP1xP1(tmp1) // now v = 16*(odd components) + + // Accumulate the even components + for i := 0; i < 64; i += 2 { + basepointTable[i/2].SelectInto(multiple, digits[i]) + tmp1.AddAffine(v, multiple) + v.fromP1xP1(tmp1) + } + + return v +} + +// ScalarMult sets v = x * q, and returns v. +// +// The scalar multiplication is done in constant time. +func (v *Point) ScalarMult(x *Scalar, q *Point) *Point { + checkInitialized(q) + + var table projLookupTable + table.FromP3(q) + + // Write x = sum(x_i * 16^i) + // so x*Q = sum( Q*x_i*16^i ) + // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... ) + // <------compute inside out--------- + // + // We use the lookup table to get the x_i*Q values + // and do four doublings to compute 16*Q + digits := x.signedRadix16() + + // Unwrap first loop iteration to save computing 16*identity + multiple := &projCached{} + tmp1 := &projP1xP1{} + tmp2 := &projP2{} + table.SelectInto(multiple, digits[63]) + + v.Set(NewIdentityPoint()) + tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords + for i := 62; i >= 0; i-- { + tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords + tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords + tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords + v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords + table.SelectInto(multiple, digits[i]) + tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords + } + v.fromP1xP1(tmp1) + return v +} + +// basepointNafTable is the nafLookupTable8 for the basepoint. +// It is precomputed the first time it's used. +func basepointNafTable() *nafLookupTable8 { + basepointNafTablePrecomp.initOnce.Do(func() { + basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint()) + }) + return &basepointNafTablePrecomp.table +} + +var basepointNafTablePrecomp struct { + table nafLookupTable8 + initOnce sync.Once +} + +// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical +// generator, and returns v. +// +// Execution time depends on the inputs. +func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point { + checkInitialized(A) + + // Similarly to the single variable-base approach, we compute + // digits and use them with a lookup table. However, because + // we are allowed to do variable-time operations, we don't + // need constant-time lookups or constant-time digit + // computations. + // + // So we use a non-adjacent form of some width w instead of + // radix 16. This is like a binary representation (one digit + // for each binary place) but we allow the digits to grow in + // magnitude up to 2^{w-1} so that the nonzero digits are as + // sparse as possible. Intuitively, this "condenses" the + // "mass" of the scalar onto sparse coefficients (meaning + // fewer additions). + + basepointNafTable := basepointNafTable() + var aTable nafLookupTable5 + aTable.FromP3(A) + // Because the basepoint is fixed, we can use a wider NAF + // corresponding to a bigger table. + aNaf := a.nonAdjacentForm(5) + bNaf := b.nonAdjacentForm(8) + + // Find the first nonzero coefficient. + i := 255 + for j := i; j >= 0; j-- { + if aNaf[j] != 0 || bNaf[j] != 0 { + break + } + } + + multA := &projCached{} + multB := &affineCached{} + tmp1 := &projP1xP1{} + tmp2 := &projP2{} + tmp2.Zero() + + // Move from high to low bits, doubling the accumulator + // at each iteration and checking whether there is a nonzero + // coefficient to look up a multiple of. + for ; i >= 0; i-- { + tmp1.Double(tmp2) + + // Only update v if we have a nonzero coeff to add in. + if aNaf[i] > 0 { + v.fromP1xP1(tmp1) + aTable.SelectInto(multA, aNaf[i]) + tmp1.Add(v, multA) + } else if aNaf[i] < 0 { + v.fromP1xP1(tmp1) + aTable.SelectInto(multA, -aNaf[i]) + tmp1.Sub(v, multA) + } + + if bNaf[i] > 0 { + v.fromP1xP1(tmp1) + basepointNafTable.SelectInto(multB, bNaf[i]) + tmp1.AddAffine(v, multB) + } else if bNaf[i] < 0 { + v.fromP1xP1(tmp1) + basepointNafTable.SelectInto(multB, -bNaf[i]) + tmp1.SubAffine(v, multB) + } + + tmp2.FromP1xP1(tmp1) + } + + v.fromP2(tmp2) + return v +} diff --git a/vendor/filippo.io/edwards25519/tables.go b/vendor/filippo.io/edwards25519/tables.go new file mode 100644 index 0000000000..beec956bf7 --- /dev/null +++ b/vendor/filippo.io/edwards25519/tables.go @@ -0,0 +1,129 @@ +// Copyright (c) 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package edwards25519 + +import ( + "crypto/subtle" +) + +// A dynamic lookup table for variable-base, constant-time scalar muls. +type projLookupTable struct { + points [8]projCached +} + +// A precomputed lookup table for fixed-base, constant-time scalar muls. +type affineLookupTable struct { + points [8]affineCached +} + +// A dynamic lookup table for variable-base, variable-time scalar muls. +type nafLookupTable5 struct { + points [8]projCached +} + +// A precomputed lookup table for fixed-base, variable-time scalar muls. +type nafLookupTable8 struct { + points [64]affineCached +} + +// Constructors. + +// Builds a lookup table at runtime. Fast. +func (v *projLookupTable) FromP3(q *Point) { + // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q + // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q + v.points[0].FromP3(q) + tmpP3 := Point{} + tmpP1xP1 := projP1xP1{} + for i := 0; i < 7; i++ { + // Compute (i+1)*Q as Q + i*Q and convert to a ProjCached + // This is needlessly complicated because the API has explicit + // recievers instead of creating stack objects and relying on RVO + v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i]))) + } +} + +// This is not optimised for speed; fixed-base tables should be precomputed. +func (v *affineLookupTable) FromP3(q *Point) { + // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q + // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q + v.points[0].FromP3(q) + tmpP3 := Point{} + tmpP1xP1 := projP1xP1{} + for i := 0; i < 7; i++ { + // Compute (i+1)*Q as Q + i*Q and convert to AffineCached + v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i]))) + } +} + +// Builds a lookup table at runtime. Fast. +func (v *nafLookupTable5) FromP3(q *Point) { + // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q + // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q + v.points[0].FromP3(q) + q2 := Point{} + q2.Add(q, q) + tmpP3 := Point{} + tmpP1xP1 := projP1xP1{} + for i := 0; i < 7; i++ { + v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i]))) + } +} + +// This is not optimised for speed; fixed-base tables should be precomputed. +func (v *nafLookupTable8) FromP3(q *Point) { + v.points[0].FromP3(q) + q2 := Point{} + q2.Add(q, q) + tmpP3 := Point{} + tmpP1xP1 := projP1xP1{} + for i := 0; i < 63; i++ { + v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i]))) + } +} + +// Selectors. + +// Set dest to x*Q, where -8 <= x <= 8, in constant time. +func (v *projLookupTable) SelectInto(dest *projCached, x int8) { + // Compute xabs = |x| + xmask := x >> 7 + xabs := uint8((x + xmask) ^ xmask) + + dest.Zero() + for j := 1; j <= 8; j++ { + // Set dest = j*Q if |x| = j + cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) + dest.Select(&v.points[j-1], dest, cond) + } + // Now dest = |x|*Q, conditionally negate to get x*Q + dest.CondNeg(int(xmask & 1)) +} + +// Set dest to x*Q, where -8 <= x <= 8, in constant time. +func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) { + // Compute xabs = |x| + xmask := x >> 7 + xabs := uint8((x + xmask) ^ xmask) + + dest.Zero() + for j := 1; j <= 8; j++ { + // Set dest = j*Q if |x| = j + cond := subtle.ConstantTimeByteEq(xabs, uint8(j)) + dest.Select(&v.points[j-1], dest, cond) + } + // Now dest = |x|*Q, conditionally negate to get x*Q + dest.CondNeg(int(xmask & 1)) +} + +// Given odd x with 0 < x < 2^4, return x*Q (in variable time). +func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) { + *dest = v.points[x/2] +} + +// Given odd x with 0 < x < 2^7, return x*Q (in variable time). +func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) { + *dest = v.points[x/2] +} diff --git a/vendor/github.com/bwesterb/go-ristretto/.travis.yml b/vendor/github.com/bwesterb/go-ristretto/.travis.yml new file mode 100644 index 0000000000..a66ae4fede --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: + - "1.x" + - "1.8" + - "1.10.x" + - "1.11.x" + - "1.12.x" + - "1.13.x" + - master diff --git a/vendor/github.com/bwesterb/go-ristretto/LICENSE b/vendor/github.com/bwesterb/go-ristretto/LICENSE new file mode 100644 index 0000000000..9ea6a4e238 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Bas Westerbaan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/bwesterb/go-ristretto/README.md b/vendor/github.com/bwesterb/go-ristretto/README.md new file mode 100644 index 0000000000..8fa22ea706 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/README.md @@ -0,0 +1,111 @@ +go-ristretto +============ + +Many cryptographic schemes need a group of prime order. Popular and +efficient elliptic curves like (Edwards25519 of `ed25519` fame) are +rarely of prime order. There is, however, a convenient method +to construct a prime order group from such curves, +called [Ristretto](https://ristretto.group) proposed by +[Mike Hamburg](https://www.shiftleft.org). + +This is a pure Go implementation of the group operations on the +Ristretto prime-order group built from Edwards25519. +Documentation is on [godoc](https://godoc.org/github.com/bwesterb/go-ristretto). + +Example: El'Gamal encryption +---------------------------- + +```go +// Generate an El'Gamal keypair +var secretKey ristretto.Scalar +var publicKey ristretto.Point + +secretKey.Rand() // generate a new secret key +publicKey.ScalarMultBase(&secretKey) // compute public key + +// El'Gamal encrypt a random curve point p into a ciphertext-pair (c1,c2) +var p ristretto.Point +var r ristretto.Scalar +var c1 ristretto.Point +var c2 ristretto.Point +p.Rand() +r.Rand() +c2.ScalarMultBase(&r) +c1.PublicScalarMult(&publicKey, &r) +c1.Add(&c1, &p) + +// Decrypt (c1,c2) back to p +var blinding, p2 ristretto.Point +blinding.ScalarMult(&c2, &secretKey) +p2.Sub(&c1, &blinding) + +fmt.Printf("%v", bytes.Equal(p.Bytes(), p2.Bytes())) +// Output: +// true +``` + +Compatibility with `ristretto255` RFC draft +------------------------------------------- + +An [RFC has been proposed](https://datatracker.ietf.org/doc/draft-hdevalence-cfrg-ristretto/) +to standardise Ristretto over Ed25519. This RFC is compatible with `go-ristretto`. There +is one caveat: one should use `Point.DeriveDalek` instead of `Point.Derive` to derive a point +from a string. + + +References +---------- + +The curve and Ristretto implementation is based on the unpublished +[PandA](https://link.springer.com/chapter/10.1007/978-3-319-04873-4_14) +library by +[Chuengsatiansup](https://perso.ens-lyon.fr/chitchanok.chuengsatiansup/), +[Ribarski](http://panceribarski.com) and +[Schwabe](https://cryptojedi.org/peter/index.shtml), +see [cref/cref.c](cref/cref.c). The old generic radix 25.5 field operations borrow +from [Adam Langley](https://www.imperialviolet.org)'s +[ed25519](http://github.com/agl/ed25519). +The amd64 optimized field arithmetic are from George Tankersley's +[ed25519 patch](https://go-review.googlesource.com/c/crypto/+/71950), +which in turn is based on SUPERCOP's +[`amd64-51-30k`](https://github.com/floodyberry/supercop/tree/master/crypto_sign/ed25519/amd64-51-30k) +by Bernstein, Duif, Lange, Schwabe and Yang. +The new generic radix 51 field operations are also based on `amd64-51-30k`. +The variable-time scalar multiplication code is based on that +of [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). +The Lizard encoding was proposed by [Bram Westerbaan](https://bram.westerbaan.name/). +The quick RistrettoElligator inversion for it is joint work +with [Bram Westerbaan](https://bram.westerbaan.name/) +and [Mike Hamburg](https://www.shiftleft.org). + +### other platforms +* [Rust](https://github.com/dalek-cryptography/curve25519-dalek) +* [Javascript](https://github.com/jedisct1/wasm-crypto) +* [C (part of `libsodium`)](https://libsodium.gitbook.io/doc/advanced/point-arithmetic/ristretto) + + +Changes +------- + +### 1.2.0 (17-02-2021) + +- Add Point.Double(). See issue #21. +- To align more closely with the RFC, Point.SetBytes() + and Point.UnmarshalBinary() will now reject points with non-canonical + encodings. See #20. + +### 1.1.1 (24-09-2019) + +- Only use bits.Add64 from Go 1.13 onwards to make sure we're constant-time + on non-amd64 platforms. Thanks @Yawning; see issue #17. + +### 1.1.0 (13-05-2019) + +- Add support for the Lizard 16-bytes-to-point-injection. + See `ristretto.Point.`{`SetLizard()`, `Lizard()`,`LizardInto()`}. +- Add `Scalar.DeriveShort()` to derive a half-length scalar. + (Warning: half-length scalars are unsafe in almost every application.) + +- (internal) Add `ExtendedPoint.RistrettoElligator2Inverse()` to compute + all preimages of a given point up-to Ristretto equivalence + of `CompletedPoint.SetRistrettoElligator2()`. diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/curve.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/curve.go new file mode 100644 index 0000000000..2383acb05d --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/curve.go @@ -0,0 +1,442 @@ +// Go implementation of the elliptic curve Edwards25519 of which the +// Ristretto group is a subquotient. +package edwards25519 + +import ( + "crypto/subtle" + "encoding/hex" + "fmt" +) + +// (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, X*Y=Z*T. Aka P3. +type ExtendedPoint struct { + X, Y, Z, T FieldElement +} + +// ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T. Aka P1P1. +type CompletedPoint struct { + X, Y, Z, T FieldElement +} + +// (X:Y:Z) satisfying x=X/Z, y=Y/Z. +type ProjectivePoint struct { + X, Y, Z FieldElement +} + +// Set p to (-i,0), a point Ristretto-equivalent to 0. Returns p. +func (p *ExtendedPoint) SetTorsion3() *ExtendedPoint { + p.X.Set(&feMinusI) + p.Y.SetZero() + p.Z.Set(&feOne) + p.T.SetZero() + return p +} + +// Set p to (i,0), a point Ristretto-equivalent to 0. Returns p. +func (p *ExtendedPoint) SetTorsion2() *ExtendedPoint { + p.X.Set(&feI) + p.Y.SetZero() + p.Z.Set(&feOne) + p.T.SetZero() + return p +} + +// Set p to (0,-1), a point Ristretto-equivalent to 0. Returns p. +func (p *ExtendedPoint) SetTorsion1() *ExtendedPoint { + p.X.SetZero() + p.Y.Set(&feMinusOne) + p.Z.Set(&feOne) + p.T.SetZero() + return p +} + +// Set p to zero, the neutral element. Return p. +func (p *ProjectivePoint) SetZero() *ProjectivePoint { + p.X.SetZero() + p.Y.SetOne() + p.Z.SetOne() + return p +} + +// Set p to zero, the neutral element. Return p. +func (p *ExtendedPoint) SetZero() *ExtendedPoint { + p.X.SetZero() + p.Y.SetOne() + p.Z.SetOne() + p.T.SetZero() + return p +} + +// Set p to the basepoint (x,4/5) with x>=0. Returns p +func (p *ExtendedPoint) SetBase() *ExtendedPoint { + return p.Set(&epBase) +} + +// Set p to q. Returns p. +func (p *ExtendedPoint) Set(q *ExtendedPoint) *ExtendedPoint { + p.X.Set(&q.X) + p.Y.Set(&q.Y) + p.Z.Set(&q.Z) + p.T.Set(&q.T) + return p +} + +// Set p to q if b == 1. Assumes b is 0 or 1. Returns p. +func (p *ExtendedPoint) ConditionalSet(q *ExtendedPoint, b int32) *ExtendedPoint { + p.X.ConditionalSet(&q.X, b) + p.Y.ConditionalSet(&q.Y, b) + p.Z.ConditionalSet(&q.Z, b) + p.T.ConditionalSet(&q.T, b) + return p +} + +// Sets p to q+r. Returns p +func (p *CompletedPoint) AddExtended(q, r *ExtendedPoint) *CompletedPoint { + var a, b, c, d, t FieldElement + + a.sub(&q.Y, &q.X) + t.sub(&r.Y, &r.X) + a.Mul(&a, &t) + b.add(&q.X, &q.Y) + t.add(&r.X, &r.Y) + b.Mul(&b, &t) + c.Mul(&q.T, &r.T) + c.Mul(&c, &fe2D) + d.Mul(&q.Z, &r.Z) + d.add(&d, &d) + p.X.sub(&b, &a) + p.T.sub(&d, &c) + p.Z.add(&d, &c) + p.Y.add(&b, &a) + + return p +} + +// Sets p to q-r. Returns p +func (p *CompletedPoint) SubExtended(q, r *ExtendedPoint) *CompletedPoint { + var a, b, c, d, t FieldElement + + a.sub(&q.Y, &q.X) + t.add(&r.Y, &r.X) + a.Mul(&a, &t) + b.add(&q.X, &q.Y) + t.sub(&r.Y, &r.X) + b.Mul(&b, &t) + c.Mul(&q.T, &r.T) + c.Mul(&c, &fe2D) + d.Mul(&q.Z, &r.Z) + d.add(&d, &d) + p.X.sub(&b, &a) + p.T.add(&d, &c) + p.Z.sub(&d, &c) + p.Y.add(&b, &a) + + return p +} + +// Set p to 2 * q. Returns p. +func (p *CompletedPoint) DoubleProjective(q *ProjectivePoint) *CompletedPoint { + var t0 FieldElement + + p.X.Square(&q.X) + p.Z.Square(&q.Y) + p.T.DoubledSquare(&q.Z) + p.Y.add(&q.X, &q.Y) + t0.Square(&p.Y) + p.Y.add(&p.Z, &p.X) + p.Z.sub(&p.Z, &p.X) + p.X.sub(&t0, &p.Y) + p.T.sub(&p.T, &p.Z) + + return p +} + +// Set p to 2 * q. Returns p. +func (p *CompletedPoint) DoubleExtended(q *ExtendedPoint) *CompletedPoint { + var a, b, c, d FieldElement + + a.Square(&q.X) + b.Square(&q.Y) + c.DoubledSquare(&q.Z) + d.Neg(&a) + p.X.add(&q.X, &q.Y) + p.X.Square(&p.X) + p.X.sub(&p.X, &a) + p.X.sub(&p.X, &b) + p.Z.add(&d, &b) + p.T.sub(&p.Z, &c) + p.Y.sub(&d, &b) + + return p +} + +// Set p to q. Returns p. +func (p *ProjectivePoint) SetExtended(q *ExtendedPoint) *ProjectivePoint { + p.X.Set(&q.X) + p.Y.Set(&q.Y) + p.Z.Set(&q.Z) + return p +} + +// Set p to q. Returns p. +func (p *ProjectivePoint) SetCompleted(q *CompletedPoint) *ProjectivePoint { + p.X.Mul(&q.X, &q.T) + p.Y.Mul(&q.Y, &q.Z) + p.Z.Mul(&q.Z, &q.T) + return p +} + +// Set p to 2 * q. Returns p. +func (p *ExtendedPoint) Double(q *ExtendedPoint) *ExtendedPoint { + var tmp CompletedPoint + tmp.DoubleExtended(q) + p.SetCompleted(&tmp) + return p +} + +// Set p to q + r. Returns p. +func (p *ExtendedPoint) Add(q, r *ExtendedPoint) *ExtendedPoint { + var tmp CompletedPoint + tmp.AddExtended(q, r) + p.SetCompleted(&tmp) + return p +} + +// Set p to q - r. Returns p. +func (p *ExtendedPoint) Sub(q, r *ExtendedPoint) *ExtendedPoint { + var tmp CompletedPoint + tmp.SubExtended(q, r) + p.SetCompleted(&tmp) + return p +} + +// Sets p to q. Returns p. +func (p *ExtendedPoint) SetCompleted(q *CompletedPoint) *ExtendedPoint { + p.X.Mul(&q.X, &q.T) + p.Y.Mul(&q.Y, &q.Z) + p.Z.Mul(&q.Z, &q.T) + p.T.Mul(&q.X, &q.Y) + return p +} + +// Set p to a point corresponding to the encoded group element of +// the ristretto group. Returns whether the buffer encoded a group element. +func (p *ExtendedPoint) SetRistretto(buf *[32]byte) bool { + var s, s2, chk, yDen, yNum, yDen2, xDen2, isr, xDenInv FieldElement + var yDenInv, t FieldElement + var b, ret int32 + var buf2 [32]byte + + s.SetBytes(buf) + + // ensures 0 ≤ s < 2^255-19 + s.BytesInto(&buf2) + ret = int32(1 - subtle.ConstantTimeCompare(buf[:], buf2[:])) + ret |= int32(buf2[0] & 1) // ensure s is positive + + s2.Square(&s) + yDen.add(&feOne, &s2) + yNum.sub(&feOne, &s2) + yDen2.Square(&yDen) + xDen2.Square(&yNum) + xDen2.Mul(&xDen2, &feD) + xDen2.add(&xDen2, &yDen2) + xDen2.Neg(&xDen2) + t.Mul(&xDen2, &yDen2) + isr.InvSqrt(&t) + chk.Square(&isr) + chk.Mul(&chk, &t) + ret |= 1 - chk.IsOneI() + xDenInv.Mul(&isr, &yDen) + yDenInv.Mul(&xDenInv, &isr) + yDenInv.Mul(&yDenInv, &xDen2) + p.X.Mul(&s, &xDenInv) + p.X.add(&p.X, &p.X) + b = p.X.IsNegativeI() + t.Neg(&p.X) + p.X.ConditionalSet(&t, b) + p.Y.Mul(&yNum, &yDenInv) + p.Z.SetOne() + p.T.Mul(&p.X, &p.Y) + ret |= p.T.IsNegativeI() + ret |= 1 - p.Y.IsNonZeroI() + p.X.ConditionalSet(&feZero, ret) + p.Y.ConditionalSet(&feZero, ret) + p.Z.ConditionalSet(&feZero, ret) + p.T.ConditionalSet(&feZero, ret) + return ret == 0 +} + +// Pack p using the Ristretto encoding and return it. +// Requires p to be even. +func (p *ExtendedPoint) Ristretto() []byte { + var buf [32]byte + p.RistrettoInto(&buf) + return buf[:] +} + +// Pack p using the Ristretto encoding and write to buf. Returns p. +// Requires p to be even. +func (p *ExtendedPoint) RistrettoInto(buf *[32]byte) *ExtendedPoint { + var d, u1, u2, isr, i1, i2, zInv, denInv, nx, ny, s FieldElement + var b int32 + + d.add(&p.Z, &p.Y) + u1.sub(&p.Z, &p.Y) + u1.Mul(&u1, &d) + + u2.Mul(&p.X, &p.Y) + + isr.Square(&u2) + isr.Mul(&isr, &u1) + isr.InvSqrt(&isr) + + i1.Mul(&isr, &u1) + i2.Mul(&isr, &u2) + + zInv.Mul(&i1, &i2) + zInv.Mul(&zInv, &p.T) + + d.Mul(&zInv, &p.T) + + nx.Mul(&p.Y, &feI) + ny.Mul(&p.X, &feI) + denInv.Mul(&feInvSqrtMinusDMinusOne, &i1) + + b = 1 - d.IsNegativeI() + nx.ConditionalSet(&p.X, b) + ny.ConditionalSet(&p.Y, b) + denInv.ConditionalSet(&i2, b) + + d.Mul(&nx, &zInv) + b = d.IsNegativeI() + d.Neg(&ny) + ny.ConditionalSet(&d, b) + + s.sub(&p.Z, &ny) + s.Mul(&s, &denInv) + + b = s.IsNegativeI() + d.Neg(&s) + s.ConditionalSet(&d, b) + + s.BytesInto(buf) + return p +} + +// Compute 5-bit window for the scalar s. +func computeScalarWindow5(s *[32]byte, w *[51]int8) { + for i := 0; i < 6; i++ { + w[8*i+0] = int8(s[5*i+0] & 31) + w[8*i+1] = int8((s[5*i+0] >> 5) & 31) + w[8*i+1] ^= int8((s[5*i+1] << 3) & 31) + w[8*i+2] = int8((s[5*i+1] >> 2) & 31) + w[8*i+3] = int8((s[5*i+1] >> 7) & 31) + w[8*i+3] ^= int8((s[5*i+2] << 1) & 31) + w[8*i+4] = int8((s[5*i+2] >> 4) & 31) + w[8*i+4] ^= int8((s[5*i+3] << 4) & 31) + w[8*i+5] = int8((s[5*i+3] >> 1) & 31) + w[8*i+6] = int8((s[5*i+3] >> 6) & 31) + w[8*i+6] ^= int8((s[5*i+4] << 2) & 31) + w[8*i+7] = int8((s[5*i+4] >> 3) & 31) + } + w[8*6+0] = int8(s[5*6+0] & 31) + w[8*6+1] = int8((s[5*6+0] >> 5) & 31) + w[8*6+1] ^= int8((s[5*6+1] << 3) & 31) + w[8*6+2] = int8((s[5*6+1] >> 2) & 31) + + /* Making it signed */ + var carry int8 = 0 + for i := 0; i < 50; i++ { + w[i] += carry + w[i+1] += w[i] >> 5 + w[i] &= 31 + carry = w[i] >> 4 + w[i] -= carry << 5 + } + w[50] += carry +} + +// Set p to s * q. Returns p. +func (p *ExtendedPoint) ScalarMult(q *ExtendedPoint, s *[32]byte) *ExtendedPoint { + // See eg. https://cryptojedi.org/peter/data/eccss-20130911b.pdf + var lut [17]ExtendedPoint + var t ExtendedPoint + var window [51]int8 + + // Precomputations. + computeScalarWindow5(s, &window) + lut[0].SetZero() + lut[1].Set(q) + for i := 2; i < 16; i += 2 { + lut[i].Double(&lut[i>>1]) + lut[i+1].Add(&lut[i], q) + } + lut[16].Double(&lut[8]) + + // Compute! + p.SetZero() + for i := 50; i >= 0; i-- { + var pp ProjectivePoint + var cp CompletedPoint + cp.DoubleExtended(p) + for z := 0; z < 4; z++ { + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + } + p.SetCompleted(&cp) + + t.Set(&lut[0]) + b := int32(window[i]) + for j := 1; j <= 16; j++ { + c := equal15(b, int32(-j)) | equal15(b, int32(j)) + t.ConditionalSet(&lut[j], c) + } + var v FieldElement + c := negative(b) + v.Neg(&t.X) + t.X.ConditionalSet(&v, c) + v.Neg(&t.T) + t.T.ConditionalSet(&v, c) + + p.Add(p, &t) + } + + return p +} + +// Sets p to -q. Returns p. +func (p *ExtendedPoint) Neg(q *ExtendedPoint) *ExtendedPoint { + p.X.Neg(&q.X) + p.Y.Set(&q.Y) + p.Z.Set(&q.Z) + p.T.Neg(&q.T) + return p +} + +// Returns 1 if p and q are in the same Ristretto equivalence class. +// Assumes p and q are both even. +func (p *ExtendedPoint) RistrettoEqualsI(q *ExtendedPoint) int32 { + var x1y2, x2y1, x1x2, y1y2 FieldElement + x1y2.Mul(&p.X, &q.Y) + x2y1.Mul(&q.X, &p.Y) + x1x2.Mul(&p.X, &q.X) + y1y2.Mul(&p.Y, &q.Y) + return 1 - ((1 - x1y2.EqualsI(&x2y1)) & (1 - x1x2.EqualsI(&y1y2))) +} + +// WARNING This operation is not constant-time. Do not use for cryptography +// unless you're sure this is not an issue. +func (p *ExtendedPoint) String() string { + return fmt.Sprintf("ExtendedPoint(%v, %v, %v, %v; %v)", + p.X, p.Y, p.Z, p.T, hex.EncodeToString(p.Ristretto())) +} + +// WARNING This operation is not constant-time. Do not use for cryptography +// unless you're sure this is not an issue. +func (p *CompletedPoint) String() string { + var ep ExtendedPoint + ep.SetCompleted(p) + return fmt.Sprintf("CompletedPoint(%v, %v, %v, %v; %v)", + p.X, p.Y, p.Z, p.T, hex.EncodeToString(ep.Ristretto())) +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/elligator.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/elligator.go new file mode 100644 index 0000000000..19bf7e5f84 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/elligator.go @@ -0,0 +1,272 @@ +package edwards25519 + +import ( + "fmt" +) + +// Represents a point (s, t) on the Jacobi quartic associated to +// the Edwards curve +type JacobiPoint struct { + S, T FieldElement +} + +// Computes the at most 8 positive FieldElements f such that p == elligator2(f). +// Assumes p is even. +// +// Returns a bitmask of which elements in fes are set. +func (p *ExtendedPoint) RistrettoElligator2Inverse(fes *[8]FieldElement) uint8 { + var setMask uint8 + var jcs [4]JacobiPoint + var jc JacobiPoint + + // Elligator2 computes a Point from a FieldElement in two steps: first + // it computes a (s,t) on the Jacobi quartic and then computes the + // corresponding even point on the Edwards curve. + // + // We invert in three steps. Any Ristretto point has four representatives + // as even Edwards points. For each of those even Edwards points, + // there are two points on the Jacobi quartic that map to it. + // Each of those eight points on the Jacobi quartic might have an + // Elligator2 preimage. + // + // Essentially we first loop over the four representatives of our point, + // then for each of them consider both points on the Jacobi quartic and + // check whether they have an inverse under Elligator2. We take the + // following shortcut though. + // + // We can compute two Jacobi quartic points for (x,y) and (-x,-y) + // at the same time. The four Jacobi quartic points are two of + // such pairs. + + p.ToJacobiQuarticRistretto(&jcs) + + for j := 0; j < 4; j++ { + setMask |= uint8(jcs[j].elligator2Inverse(&fes[2*j]) << uint(2*j)) + jc.Dual(&jcs[j]) + setMask |= uint8(jc.elligator2Inverse(&fes[2*j+1]) << uint(2*j+1)) + } + + return setMask +} + +// Find a point on the Jacobi quartic associated to each of the four +// points Ristretto equivalent to p. +// +// There is one exception: for (0,-1) there is no point on the quartic and +// so we repeat one on the quartic equivalent to (0,1). +func (p *ExtendedPoint) ToJacobiQuarticRistretto(qs *[4]JacobiPoint) *ExtendedPoint { + var X2, Y2, Z2, Y4, ZmY, ZpY, Z2mY2, gamma, den, sOverX, spOverXp, tmp FieldElement + + X2.Square(&p.X) // X^2 + Y2.Square(&p.Y) // Y^2 + Y4.Square(&Y2) // Y^4 + Z2.Square(&p.Z) // Z^2 + ZmY.sub(&p.Z, &p.Y) // Z - Y + ZpY.add(&p.Z, &p.Y) // Z + Y + Z2mY2.sub(&Z2, &Y2) // Z^2 - Y^2 + + // gamma := 1/sqrt( Y^4 X^2 (Z^2 - Y^2) ) + gamma.Mul(&Y4, &X2) + gamma.Mul(&gamma, &Z2mY2) + gamma.InvSqrt(&gamma) + + // den := gamma * Y^2 + den.Mul(&gamma, &Y2) + + // sOverX := den * (Z - Y) + // spOverXp := den * (Z + Y) + sOverX.Mul(&den, &ZmY) + spOverXp.Mul(&den, &ZpY) + + // s_0 := sOverX * X + // s_1 := -spOverXp * X + qs[0].S.Mul(&sOverX, &p.X) + tmp.Mul(&spOverXp, &p.X) + qs[1].S.Neg(&tmp) + + // t_0 := 2/sqrt(-d-1) * Z * sOverX + // t_1 := 2/sqrt(-d-1) * Z * spOverXp + tmp.Mul(&feDoubleInvSqrtMinusDMinusOne, &p.Z) + qs[0].T.Mul(&tmp, &sOverX) + qs[1].T.Mul(&tmp, &spOverXp) + + // den = 1/sqrt(1+d) (Y^2 - Z^2) gamma + den.Neg(&Z2mY2) + den.Mul(&den, &feInvSqrt1pD) + den.Mul(&den, &gamma) + + // Same as before, but with the substitution (X, Y, Z) = (Y, X, i*Z) + var iZ, iZmX, iZpX, sOverY, spOverYp FieldElement + iZ.Mul(&feI, &p.Z) // iZ + iZmX.sub(&iZ, &p.X) // iZ - X + iZpX.add(&iZ, &p.X) // iZ + X + + // sOverY := den * (iZ - Y) + // spOverYp := den * (iZ + Y) + sOverY.Mul(&den, &iZmX) + spOverYp.Mul(&den, &iZpX) + + // s_2 := sOverY * Y + // s_3 := -spOverYp * Y + qs[2].S.Mul(&sOverY, &p.Y) + tmp.Mul(&spOverYp, &p.Y) + qs[3].S.Neg(&tmp) + + // t_2 := 2/sqrt(-d-1) * i*Z * sOverY + // t_3 := 2/sqrt(-d-1) * i*Z * spOverYp + tmp.Mul(&feDoubleInvSqrtMinusDMinusOne, &iZ) + qs[2].T.Mul(&tmp, &sOverY) + qs[3].T.Mul(&tmp, &spOverYp) + + // Special case: X=0 or Y=0. Then return + // + // (0,1) (1,2i/sqrt(-d-1) (-1,2i/sqrt(-d-1)) + // + // Note that if X=0 or Y=0, then s_i = t_i = 0. + XorYisZero := 1 - (p.X.IsNonZeroI() & p.Y.IsNonZeroI()) + qs[0].T.ConditionalSet(&feOne, XorYisZero) + qs[1].T.ConditionalSet(&feOne, XorYisZero) + qs[2].T.ConditionalSet(&feDoubleIInvSqrtMinusDMinusOne, XorYisZero) + qs[3].T.ConditionalSet(&feDoubleIInvSqrtMinusDMinusOne, XorYisZero) + qs[2].S.ConditionalSet(&feOne, XorYisZero) + qs[3].S.ConditionalSet(&feMinusOne, XorYisZero) + + return p +} + +func (p *JacobiPoint) Dual(q *JacobiPoint) *JacobiPoint { + p.S.Neg(&q.S) + p.T.Neg(&q.T) + + return p +} + +// Elligator2 is defined in two steps: first a field element is converted +// to a point (s,t) on the Jacobi quartic associated to the Edwards curve. +// Then this point is mapped to a point on the Edwards curve. +// This function computes a field element that is mapped to a given (s,t) +// with Elligator2 if it exists. +// +// Returns 1 if a preimage is found and 0 if none exists. +func (p *JacobiPoint) elligator2Inverse(fe *FieldElement) int { + var x, y, a, a2, S2, S4, invSqiY, negS2, out FieldElement + + // Special case: s = 0. If s is zero, either t = 1 or t = -1. + // If t=1, then sqrt(i*d) is the preimage. Otherwise it's 0. + + sNonZero := p.S.IsNonZeroI() + tEqualsOne := p.T.EqualsI(&feOne) + out.Set(&feZero) + out.ConditionalSet(&feSqrtID, tEqualsOne) + + ret := 1 - sNonZero + done := 1 - sNonZero + + // a := (t+1) (d+1)/(d-1) + a.add(&p.T, &feOne) + a.Mul(&a, &feDp1OverDm1) + a2.Square(&a) + + // y := 1/sqrt(i (s^4 - a^2)). + S2.Square(&p.S) + S4.Square(&S2) + invSqiY.sub(&S4, &a2) + + // there is no preimage of the square root of i*(s^4-a^2) does not exist + sq := y.InvSqrtI(&invSqiY) + ret |= 1 - sq + done |= sq + + // x := (a + sign(s)*s^2) y + negS2.Neg(&S2) + S2.ConditionalSet(&negS2, p.S.IsNegativeI()) + x.add(&a, &S2) + x.Mul(&x, &y) + + // fe := abs(x) + x.Abs(&x) + out.ConditionalSet(&x, 1-done) + fe.Set(&out) + + return int(ret) +} + +// Set p to the point corresponding to the given point (s,t) on the +// associated Jacobi quartic. +func (p *CompletedPoint) SetJacobiQuartic(jc *JacobiPoint) *CompletedPoint { + var s2 FieldElement + s2.Square(&jc.S) + + // Set x to s * 2/sqrt(-d-1) + p.X.Mul(&jc.S, &feDoubleInvSqrtMinusDMinusOne) + + // Set z to t + p.Z.Set(&jc.T) + + // Set y to 1-s^2 + p.Y.sub(&feOne, &s2) + + // Set t to 1+s^2 + p.T.add(&feOne, &s2) + return p +} + +// Set p to the curvepoint corresponding to r0 via Mike Hamburg's variation +// on Elligator2 for Ristretto. Returns p. +func (p *CompletedPoint) SetRistrettoElligator2(r0 *FieldElement) *CompletedPoint { + var r, rPlusD, rPlusOne, D, N, ND, sqrt, twiddle, sgn FieldElement + var rSubOne, r0i, sNeg FieldElement + var jc JacobiPoint + + var b int32 + + // r := i * r0^2 + r0i.Mul(r0, &feI) + r.Mul(r0, &r0i) + + // D := -((d*r)+1) * (r + d) + rPlusD.add(&feD, &r) + D.Mul(&feD, &r) + D.add(&D, &feOne) + D.Mul(&D, &rPlusD) + D.Neg(&D) + + // N := -(d^2 - 1)(r + 1) + rPlusOne.add(&r, &feOne) + N.Mul(&feOneMinusDSquared, &rPlusOne) + + // sqrt is the inverse square root of N*D or of i*N*D. + // b=1 iff n1 is square. + ND.Mul(&N, &D) + + b = sqrt.InvSqrtI(&ND) + sqrt.Abs(&sqrt) + + twiddle.SetOne() + twiddle.ConditionalSet(&r0i, 1-b) + sgn.SetOne() + sgn.ConditionalSet(&feMinusOne, 1-b) + sqrt.Mul(&sqrt, &twiddle) + + // s = N * sqrt * twiddle + jc.S.Mul(&sqrt, &N) + + // t = -sgn * sqrt * s * (r-1) * (d-1)^2 - 1 + jc.T.Neg(&sgn) + jc.T.Mul(&sqrt, &jc.T) + jc.T.Mul(&jc.S, &jc.T) + jc.T.Mul(&feDMinusOneSquared, &jc.T) + rSubOne.sub(&r, &feOne) + jc.T.Mul(&rSubOne, &jc.T) + jc.T.sub(&jc.T, &feOne) + + sNeg.Neg(&jc.S) + jc.S.ConditionalSet(&sNeg, equal30(jc.S.IsNegativeI(), b)) + return p.SetJacobiQuartic(&jc) +} + +// WARNING This operation is not constant-time. Do not use for cryptography +// unless you're sure this is not an issue. +func (p *JacobiPoint) String() string { + return fmt.Sprintf("JacobiPoint(%v, %v)", p.S, p.T) +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field.go new file mode 100644 index 0000000000..b8414dfb71 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field.go @@ -0,0 +1,353 @@ +package edwards25519 + +import ( + // Requires for FieldElement.[Set]BigInt(). Obviously not used for actual + // implementation, as operations on big.Ints are not constant-time. + "math/big" + + "encoding/binary" +) + +// Set fe to i, the root of -1. Returns fe. +func (fe *FieldElement) SetI() *FieldElement { + copy(fe[:], feI[:]) + return fe +} + +// Set fe to 0. Returns fe. +func (fe *FieldElement) SetZero() *FieldElement { + copy(fe[:], feZero[:]) + return fe +} + +// Set fe to 1. Returns fe. +func (fe *FieldElement) SetOne() *FieldElement { + copy(fe[:], feOne[:]) + return fe +} + +// Sets fe to 2*a without normalizing. Returns fe. +func (fe *FieldElement) double(a *FieldElement) *FieldElement { + return fe.add(a, a) +} + +// Sets fe to a + b. Returns fe. +func (fe *FieldElement) Add(a, b *FieldElement) *FieldElement { + return fe.add(a, b).normalize() +} + +// Sets fe to a - b. Returns fe. +func (fe *FieldElement) Sub(a, b *FieldElement) *FieldElement { + return fe.sub(a, b).normalize() +} + +// Sets fe to a. Returns fe. +func (fe *FieldElement) Set(a *FieldElement) *FieldElement { + copy(fe[:], a[:]) + return fe +} + +// Returns little endian representation of fe. +func (fe *FieldElement) Bytes() [32]byte { + var ret [32]byte + fe.BytesInto(&ret) + return ret +} + +// Set fe to the inverse of a. Return fe. +func (fe *FieldElement) Inverse(a *FieldElement) *FieldElement { + var t0, t1, t2, t3 FieldElement + var i int + + t0.Square(a) + t1.Square(&t0) + t1.Square(&t1) + t1.Mul(a, &t1) + t0.Mul(&t0, &t1) + t2.Square(&t0) + t1.Mul(&t1, &t2) + t2.Square(&t1) + for i = 1; i < 5; i++ { + t2.Square(&t2) + } + t1.Mul(&t2, &t1) + t2.Square(&t1) + for i = 1; i < 10; i++ { + t2.Square(&t2) + } + t2.Mul(&t2, &t1) + t3.Square(&t2) + for i = 1; i < 20; i++ { + t3.Square(&t3) + } + t2.Mul(&t3, &t2) + t2.Square(&t2) + for i = 1; i < 10; i++ { + t2.Square(&t2) + } + t1.Mul(&t2, &t1) + t2.Square(&t1) + for i = 1; i < 50; i++ { + t2.Square(&t2) + } + t2.Mul(&t2, &t1) + t3.Square(&t2) + for i = 1; i < 100; i++ { + t3.Square(&t3) + } + t2.Mul(&t3, &t2) + t2.Square(&t2) + for i = 1; i < 50; i++ { + t2.Square(&t2) + } + t1.Mul(&t2, &t1) + t1.Square(&t1) + for i = 1; i < 5; i++ { + t1.Square(&t1) + } + return fe.Mul(&t1, &t0) +} + +// Set fe to -x if x is negative and x otherwise. Returns fe. +func (fe *FieldElement) Abs(x *FieldElement) *FieldElement { + var xNeg FieldElement + xNeg.Neg(x) + fe.Set(x) + fe.ConditionalSet(&xNeg, x.IsNegativeI()) + return fe +} + +// Returns 1 if fe is negative, otherwise 0. +func (fe *FieldElement) IsNegativeI() int32 { + var buf [32]byte + fe.BytesInto(&buf) + return int32(buf[0] & 1) +} + +// Returns 1 if fe is non-zero, otherwise 0. +func (fe *FieldElement) IsNonZeroI() int32 { + var buf [32]byte + fe.BytesInto(&buf) + ret := (binary.LittleEndian.Uint64(buf[0:8]) | + binary.LittleEndian.Uint64(buf[8:16]) | + binary.LittleEndian.Uint64(buf[16:24]) | + binary.LittleEndian.Uint64(buf[24:32])) + ret |= ret >> 32 + ret |= ret >> 16 + ret |= ret >> 8 + ret |= ret >> 4 + ret |= ret >> 2 + ret |= ret >> 1 + return int32(ret & 1) +} + +// Returns 1 if fe is equal to one, otherwise 0. +func (fe *FieldElement) IsOneI() int32 { + var b FieldElement + return 1 - b.sub(fe, &feOne).IsNonZeroI() +} + +// Returns 1 if fe is equal to a, otherwise 0. +func (fe *FieldElement) EqualsI(a *FieldElement) int32 { + var b FieldElement + return 1 - b.sub(fe, a).IsNonZeroI() +} + +// Returns whether fe equals a. +func (fe *FieldElement) Equals(a *FieldElement) bool { + var b FieldElement + return b.sub(fe, a).IsNonZeroI() == 0 +} + +// Returns fe as a big.Int. +// +// WARNING Operations on big.Ints are not constant-time: do not use them +// for cryptography unless you're sure this is not an issue. +func (fe *FieldElement) BigInt() *big.Int { + var ret big.Int + var buf, rBuf [32]byte + fe.BytesInto(&buf) + for i := 0; i < 32; i++ { + rBuf[i] = buf[31-i] + } + return ret.SetBytes(rBuf[:]) +} + +// Writes fe as a string for debugging. +// +// WARNING This operation is not constant-time. Do not use for cryptography +// unless you're sure this is not an issue. +func (fe FieldElement) String() string { + return fe.BigInt().String() +} + +// Sets fe to x modulo 2^255-19. +// +// WARNING Operations on big.Ints are not constant-time: do not use them +// for cryptography unless you're sure this is not an issue. +func (fe *FieldElement) SetBigInt(x *big.Int) *FieldElement { + var v, bi25519 big.Int + bi25519.SetString( + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16) + buf := v.Mod(x, &bi25519).Bytes() + var rBuf [32]byte + for i := 0; i < len(buf) && i < 32; i++ { + rBuf[i] = buf[len(buf)-i-1] + } + return fe.SetBytes(&rBuf) +} + +// Sets fe to a^( ((2^255 - 19) - 5) / 8 ) = a^(2^252 - 3). Returns fe. +// +// This method is useful to compute (inverse) square-roots +// with the method of Lagrange. +func (fe *FieldElement) Exp22523(a *FieldElement) *FieldElement { + var t0, t1, t2 FieldElement + var i int + + t0.Square(a) + for i = 1; i < 1; i++ { + t0.Square(&t0) + } + t1.Square(&t0) + for i = 1; i < 2; i++ { + t1.Square(&t1) + } + t1.Mul(a, &t1) + t0.Mul(&t0, &t1) + t0.Square(&t0) + for i = 1; i < 1; i++ { + t0.Square(&t0) + } + t0.Mul(&t1, &t0) + t1.Square(&t0) + for i = 1; i < 5; i++ { + t1.Square(&t1) + } + t0.Mul(&t1, &t0) + t1.Square(&t0) + for i = 1; i < 10; i++ { + t1.Square(&t1) + } + t1.Mul(&t1, &t0) + t2.Square(&t1) + for i = 1; i < 20; i++ { + t2.Square(&t2) + } + t1.Mul(&t2, &t1) + t1.Square(&t1) + for i = 1; i < 10; i++ { + t1.Square(&t1) + } + t0.Mul(&t1, &t0) + t1.Square(&t0) + for i = 1; i < 50; i++ { + t1.Square(&t1) + } + t1.Mul(&t1, &t0) + t2.Square(&t1) + for i = 1; i < 100; i++ { + t2.Square(&t2) + } + t1.Mul(&t2, &t1) + t1.Square(&t1) + for i = 1; i < 50; i++ { + t1.Square(&t1) + } + t0.Mul(&t1, &t0) + t0.Square(&t0) + for i = 1; i < 2; i++ { + t0.Square(&t0) + } + return fe.Mul(&t0, a) +} + +// Sets fe to 1/sqrt(a). Requires a to be a square. Returns fe. +func (fe *FieldElement) InvSqrt(a *FieldElement) *FieldElement { + var den2, den3, den4, den6, chk, t, t2 FieldElement + den2.Square(a) + den3.Mul(&den2, a) + den4.Square(&den2) + den6.Mul(&den2, &den4) + t.Mul(&den6, a) + t.Exp22523(&t) + t.Mul(&t, &den3) + t2.Mul(&t, &feI) + + chk.Square(&t) + chk.Mul(&chk, a) + + fe.Set(&t) + fe.ConditionalSet(&t2, 1-chk.IsOneI()) + return fe +} + +// Sets fe to sqrt(a). Requires a to be a square. Returns fe. +func (fe *FieldElement) Sqrt(a *FieldElement) *FieldElement { + var aCopy FieldElement + aCopy.Set(a) + fe.InvSqrt(a) + fe.Mul(fe, &aCopy) + + var feNeg FieldElement + feNeg.Neg(fe) + fe.ConditionalSet(&feNeg, fe.IsNegativeI()) + return fe +} + +// Sets fe to either 1/sqrt(a) or 1/sqrt(i*a). Returns 1 in the former case +// and 0 in the latter. +func (fe *FieldElement) InvSqrtI(a *FieldElement) int32 { + var inCaseA, inCaseB, inCaseD int32 + var den2, den3, den4, den6, chk, t, corr FieldElement + den2.Square(a) + den3.Mul(&den2, a) + den4.Square(&den2) + den6.Mul(&den2, &den4) + t.Mul(&den6, a) + t.Exp22523(&t) + t.Mul(&t, &den3) + + // case A B C D + // --------------------------------------------------------------- + // t 1/sqrt(a) -i/sqrt(a) 1/sqrt(i*a) -i/sqrt(i*a) + // chk 1 -1 -i i + // corr 1 i 1 i + // ret 1 1 0 0 + + chk.Square(&t) + chk.Mul(&chk, a) + + inCaseA = chk.IsOneI() + inCaseD = chk.EqualsI(&feI) + chk.Neg(&chk) + inCaseB = chk.IsOneI() + + corr.SetOne() + corr.ConditionalSet(&feI, inCaseB+inCaseD) + t.Mul(&t, &corr) + fe.Set(&t) + + return inCaseA + inCaseB +} + +// Returns 1 if b == c and 0 otherwise. Assumes 0 <= b, c < 2^30. +func equal30(b, c int32) int32 { + x := uint32(b ^ c) + x-- + return int32(x >> 31) +} + +// Returns 1 if b == c and 0 otherwise. Assumes 2^15 <= b, c < 2^30. +func equal15(b, c int32) int32 { + ub := uint16(b) + uc := uint16(c) + x := uint32(ub ^ uc) + x-- + return int32(x >> 31) +} + +// Returns 1 if b < 0 and 0 otherwise. +func negative(b int32) int32 { + return (b >> 31) & 1 +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.go new file mode 100644 index 0000000000..0ca04a14f3 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.go @@ -0,0 +1,27 @@ +// +build amd64,!go1.13,!forcegeneric + +package edwards25519 + +//go:noescape +func feMul(out, a, b *FieldElement) + +//go:noescape +func feSquare(out, a *FieldElement) + +// Sets fe to a * b. Returns fe. +func (fe *FieldElement) Mul(a, b *FieldElement) *FieldElement { + feMul(fe, a, b) + return fe +} + +// Sets fe to a^2. Returns fe. +func (fe *FieldElement) Square(a *FieldElement) *FieldElement { + feSquare(fe, a) + return fe +} + +// Sets fe to 2 * a^2. Returns fe. +func (fe *FieldElement) DoubledSquare(a *FieldElement) *FieldElement { + feSquare(fe, a) + return fe.add(fe, fe) +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.s b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.s new file mode 100644 index 0000000000..5edfba2502 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_amd64.s @@ -0,0 +1,342 @@ +//+build amd64 AND !go1.13 + +#include "textflag.h" + +// func feMul(outp *uint64, xp *uint64, yp *uint64) +TEXT ·feMul(SB),NOSPLIT,$0 + MOVQ outp+0(FP), DI + MOVQ xp+8(FP), BX + MOVQ yp+16(FP), CX + + // Calculate r0 + MOVQ 0(BX), AX // rax <-- x0 + MULQ 0(CX) // rdx, rax <-- x0*y0 + MOVQ AX, SI // r00 = rax + MOVQ DX, BP // r01 = rdx + + MOVQ 8(BX), DX // rdx <-- x1 + IMUL3Q $19, DX, AX // rax <-- x1*19 + MULQ 32(CX) // rdx, rax <-- x1_19*y4 + ADDQ AX, SI // r00 += rax + ADCQ DX, BP // r01 += rdx + + MOVQ 16(BX), DX // rdx <-- x2 + IMUL3Q $19, DX, AX // rax <-- x2*19 + MULQ 24(CX) // rdx, rax <-- x2_19*y3 + ADDQ AX, SI // r00 += rax + ADCQ DX, BP // r01 += rdx + + MOVQ 24(BX), DX // rdx <-- x3 + IMUL3Q $19, DX, AX // rax <-- x3*19 + MULQ 16(CX) // rdx, rax <-- x3_19 * y2 + ADDQ AX, SI // r00 += rax + ADCQ DX, BP // r01 += rdx + + MOVQ 32(BX), DX // rdx <-- x4 + IMUL3Q $19, DX, AX // rax <-- x4*19 + MULQ 8(CX) // rdx rax <-- x4_19*y1 + ADDQ AX, SI // r00 += rax + ADCQ DX, BP // r01 += rdx + + // Calculate r1 + MOVQ 0(BX), AX + MULQ 8(CX) + MOVQ AX, R8 // r10 + MOVQ DX, R9 // r11 + + MOVQ 8(BX), AX + MULQ 0(CX) + ADDQ AX, R8 + ADCQ DX, R9 + + MOVQ 16(BX), DX + IMUL3Q $19, DX, AX + MULQ 32(CX) + ADDQ AX, R8 + ADCQ DX, R9 + + MOVQ 24(BX), DX + IMUL3Q $19, DX, AX + MULQ 24(CX) + ADDQ AX, R8 + ADCQ DX, R9 + + MOVQ 32(BX), DX + IMUL3Q $19, DX, AX + MULQ 16(CX) + ADDQ AX, R8 + ADCQ DX, R9 + + // Calculate r2 + MOVQ 0(BX), AX + MULQ 16(CX) + MOVQ AX, R10 // r20 + MOVQ DX, R11 // r21 + + MOVQ 8(BX), AX + MULQ 8(CX) + ADDQ AX, R10 + ADCQ DX, R11 + + MOVQ 16(BX), AX + MULQ 0(CX) + ADDQ AX, R10 + ADCQ DX, R11 + + MOVQ 24(BX), DX + IMUL3Q $19, DX, AX + MULQ 32(CX) + ADDQ AX, R10 + ADCQ DX, R11 + + MOVQ 32(BX), DX + IMUL3Q $19, DX, AX + MULQ 24(CX) + ADDQ AX, R10 + ADCQ DX, R11 + + // Calculate r3 + MOVQ 0(BX), AX + MULQ 24(CX) + MOVQ AX, R12 // r30 + MOVQ DX, R13 // r31 + + MOVQ 8(BX), AX + MULQ 16(CX) + ADDQ AX, R12 + ADCQ DX, R13 + + MOVQ 16(BX), AX + MULQ 8(CX) + ADDQ AX, R12 + ADCQ DX, R13 + + MOVQ 24(BX), AX + MULQ 0(CX) + ADDQ AX, R12 + ADCQ DX, R13 + + MOVQ 32(BX), DX + IMUL3Q $19, DX, AX + MULQ 32(CX) + ADDQ AX, R12 + ADCQ DX, R13 + + // Calculate r4 + MOVQ 0(BX), AX + MULQ 32(CX) + MOVQ AX, R14 // r40 + MOVQ DX, R15 // r41 + + MOVQ 8(BX), AX + MULQ 24(CX) + ADDQ AX, R14 + ADCQ DX, R15 + + MOVQ 16(BX), AX + MULQ 16(CX) + ADDQ AX, R14 + ADCQ DX, R15 + + MOVQ 24(BX), AX + MULQ 8(CX) + ADDQ AX, R14 + ADCQ DX, R15 + + MOVQ 32(BX), AX + MULQ 0(CX) + ADDQ AX, R14 + ADCQ DX, R15 + + + MOVQ $2251799813685247, AX // (1<<51) - 1 + SHLQ $13, SI, BP // r01 = shld with r00 + ANDQ AX, SI // r00 &= mask51 + SHLQ $13, R8, R9 // r11 = shld with r10 + ANDQ AX, R8 // r10 &= mask51 + ADDQ BP, R8 // r10 += r01 + SHLQ $13, R10, R11 // r21 = shld with r20 + ANDQ AX, R10 // r20 &= mask51 + ADDQ R9, R10 // r20 += r11 + SHLQ $13, R12, R13 // r31 = shld with r30 + ANDQ AX, R12 // r30 &= mask51 + ADDQ R11, R12 // r30 += r21 + SHLQ $13, R14, R15 // r41 = shld with r40 + ANDQ AX, R14 // r40 &= mask51 + ADDQ R13, R14 // r40 += r31 + IMUL3Q $19, R15, R15 // r41 = r41*19 + ADDQ R15, SI // r00 += r41 + + MOVQ SI, DX // rdx <-- r00 + SHRQ $51, DX // rdx <-- r00 >> 51 + ADDQ DX, R8 // r10 += r00 >> 51 + MOVQ R8, DX // rdx <-- r10 + SHRQ $51, DX // rdx <-- r10 >> 51 + ANDQ AX, SI // r00 &= mask51 + ADDQ DX, R10 // r20 += r10 >> 51 + MOVQ R10, DX // rdx <-- r20 + SHRQ $51, DX // rdx <-- r20 >> 51 + ANDQ AX, R8 // r10 &= mask51 + ADDQ DX, R12 // r30 += r20 >> 51 + MOVQ R12, DX // rdx <-- r30 + SHRQ $51, DX // rdx <-- r30 >> 51 + ANDQ AX, R10 // r20 &= mask51 + ADDQ DX, R14 // r40 += r30 >> 51 + MOVQ R14, DX // rdx <-- r40 + SHRQ $51, DX // rdx <-- r40 >> 51 + ANDQ AX, R12 // r30 &= mask51 + IMUL3Q $19, DX, DX // rdx <-- (r40 >> 51) * 19 + ADDQ DX, SI // r00 += (r40 >> 51) *19 + ANDQ AX, R14 // r40 &= mask51 + + MOVQ SI, 0(DI) + MOVQ R8, 8(DI) + MOVQ R10, 16(DI) + MOVQ R12, 24(DI) + MOVQ R14, 32(DI) + RET + +// func feSquare(outp *uint64, xp *uint64) +TEXT ·feSquare(SB),NOSPLIT,$0 + MOVQ outp+0(FP), DI + MOVQ xp+8(FP), SI + + // r0 = x0*x0 + x1*38*x4 + x2*38*x3 + MOVQ 0(SI), AX + MULQ 0(SI) + MOVQ AX, CX // r00 + MOVQ DX, R8 // r01 + + MOVQ 8(SI), DX + IMUL3Q $38, DX, AX + MULQ 32(SI) + ADDQ AX, CX + ADCQ DX, R8 + + MOVQ 16(SI), DX + IMUL3Q $38, DX, AX + MULQ 24(SI) + ADDQ AX, CX + ADCQ DX, R8 + + // r1 = x0*2*x1 + x2*38*x4 + x3*19*x3 + MOVQ 0(SI), AX + SHLQ $1, AX + MULQ 8(SI) + MOVQ AX, R9 // r10 + MOVQ DX, R10 // r11 + + MOVQ 16(SI), DX + IMUL3Q $38, DX, AX + MULQ 32(SI) + ADDQ AX, R9 + ADCQ DX, R10 + + MOVQ 24(SI), DX + IMUL3Q $19, DX, AX + MULQ 24(SI) + ADDQ AX, R9 + ADCQ DX, R10 + + // r2 = x0*2*x2 + x1*x1 + x3*38*x4 + MOVQ 0(SI), AX + SHLQ $1, AX + MULQ 16(SI) + MOVQ AX, R11 // r20 + MOVQ DX, R12 // r21 + + MOVQ 8(SI), AX + MULQ 8(SI) + ADDQ AX, R11 + ADCQ DX, R12 + + MOVQ 24(SI), DX + IMUL3Q $38, DX, AX + MULQ 32(SI) + ADDQ AX, R11 + ADCQ DX, R12 + + // r3 = x0*2*x3 + x1*2*x2 + x4*19*x4 + MOVQ 0(SI), AX + SHLQ $1, AX + MULQ 24(SI) + MOVQ AX, R13 // r30 + MOVQ DX, R14 // r31 + + MOVQ 8(SI), AX + SHLQ $1, AX + MULQ 16(SI) + ADDQ AX, R13 + ADCQ DX, R14 + + MOVQ 32(SI), DX + IMUL3Q $19, DX, AX + MULQ 32(SI) + ADDQ AX, R13 + ADCQ DX, R14 + + // r4 = x0*2*x4 + x1*2*x3 + x2*x2 + MOVQ 0(SI), AX + SHLQ $1, AX + MULQ 32(SI) + MOVQ AX, R15 // r40 + MOVQ DX, BX // r41 + + MOVQ 8(SI), AX + SHLQ $1, AX + MULQ 24(SI) + ADDQ AX, R15 + ADCQ DX, BX + + MOVQ 16(SI), AX + MULQ 16(SI) + ADDQ AX, R15 + ADCQ DX, BX + + // Reduce + MOVQ $2251799813685247, AX // (1<<51) - 1 + SHLQ $13, CX, R8 // r01 = shld with r00 + ANDQ AX, CX // r00 &= mask51 + SHLQ $13, R9, R10 // r11 = shld with r10 + ANDQ AX, R9 // r10 &= mask51 + ADDQ R8, R9 // r10 += r01 + SHLQ $13, R11, R12 // r21 = shld with r20 + ANDQ AX, R11 // r20 &= mask51 + ADDQ R10, R11 // r20 += r11 + SHLQ $13, R13, R14 // r31 = shld with r30 + ANDQ AX, R13 // r30 &= mask51 + ADDQ R12, R13 // r30 += r21 + SHLQ $13, R15, BX // r41 = shld with r40 + ANDQ AX, R15 // r40 &= mask51 + ADDQ R14, R15 // r40 += r31 + IMUL3Q $19, BX, DX // r41 = r41*19 + ADDQ DX, CX // r00 += r41 + + MOVQ CX, DX // rdx <-- r00 + SHRQ $51, DX // rdx <-- r00 >> 51 + ADDQ DX, R9 // r10 += r00 >> 51 + MOVQ R9, DX // rdx <-- r10 + SHRQ $51, DX // rdx <-- r10 >> 51 + ANDQ AX, CX // r00 &= mask51 + ADDQ DX, R11 // r20 += r10 >> 51 + MOVQ R11, DX // rdx <-- r20 + SHRQ $51, DX // rdx <-- r20 >> 51 + ANDQ AX, R9 // r10 &= mask51 + ADDQ DX, R13 // r30 += r20 >> 51 + MOVQ R13, DX // rdx <-- r30 + SHRQ $51, DX // rdx <-- r30 >> 51 + ANDQ AX, R11 // r20 &= mask51 + ADDQ DX, R15 // r40 += r30 >> 51 + MOVQ R15, DX // rdx <-- r40 + SHRQ $51, DX // rdx <-- r40 >> 51 + ANDQ AX, R13 // r30 &= mask51 + IMUL3Q $19, DX, DX // rdx <-- (r40 >> 51) * 19 + ADDQ DX, CX // r00 += (r40 >> 51) *19 + ANDQ AX, R15 // r40 &= mask51 + + MOVQ CX, 0(DI) + MOVQ R9, 8(DI) + MOVQ R11, 16(DI) + MOVQ R13, 24(DI) + MOVQ R15, 32(DI) + RET diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_generic.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_generic.go new file mode 100644 index 0000000000..f5d9d3b470 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_generic.go @@ -0,0 +1,463 @@ +// +build !amd64,!go1.13 forcegeneric + +package edwards25519 + +// Element of the field GF(2^255 - 19) over which the elliptic +// curve Edwards25519 is defined. +type FieldElement [10]int32 + +var ( + feZero FieldElement + feOne = FieldElement{1, 0, 0, 0, 0, 0, 0, 0, 0, 0} + feMinusOne = FieldElement{-1, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + // sqrt(-1) + feI = FieldElement{ + -32595792, -7943725, 9377950, 3500415, 12389472, + -272473, -25146209, -2005654, 326686, 11406482, + } + + // -sqrt(-1) + feMinusI = FieldElement{ + 32595792, 7943725, -9377950, -3500415, -12389472, + 272473, 25146209, 2005654, -326686, -11406482, + } + + // parameter d of Edwards25519 + feD = FieldElement{ + -10913610, 13857413, -15372611, 6949391, 114729, + -8787816, -6275908, -3247719, -18696448, -12055116, + } + + // double feD + fe2D = FieldElement{ + -21827239, -5839606, -30745221, 13898782, 229458, + 15978800, -12551817, -6495438, 29715968, 9444199, + } + + // 1 / sqrt(-1-d) + feInvSqrtMinusDMinusOne = FieldElement{ + -6111485, -4156064, 27798727, -12243468, 25904040, + -120897, -20826367, 7060776, -6093568, 1986012, + } + + // 2 / sqrt(-1-d) + feDoubleInvSqrtMinusDMinusOne = FieldElement{ + -12222970, -8312128, -11511410, 9067497, -15300785, + -241793, 25456130, 14121551, -12187136, 3972024, + } + + // 2i / sqrt(-1-d) + feDoubleIInvSqrtMinusDMinusOne = FieldElement{ + -8930344, -9583591, 26444492, -3752533, -26044487, + 743697, 2900628, -5634116, -25139868, 5270574, + } + + // (d-1)^2 + feDMinusOneSquared = FieldElement{ + 15551795, -11097455, -13425098, -10125071, -11896535, + 10178284, -26634327, 4729244, -5282110, -10116402, + } + + // 1 - d^2 + feOneMinusDSquared = FieldElement{ + 6275446, -16617371, -22938544, -3773710, 11667077, + 7397348, -27922721, 1766195, -24433858, 672203, + } + + // (d+1)/(d-1) + feDp1OverDm1 = FieldElement{ + -8275156, -1370137, -4651792, -7444191, 19032992, + -6350812, 7122893, -15485473, -16089458, 3776289, + } + + // sqrt(i*d) + feSqrtID = FieldElement{ + -27518040, 701139, 28659366, -9930925, -13176155, + -1348074, -30782278, -9245017, 26167231, 1494357, + } + + // 1 / sqrt(1+d) + feInvSqrt1pD = FieldElement{ + -29089260, 4791796, 20332186, -14900950, -20532188, + -371848, -1450314, 2817058, 12569934, -2635287, + } + + epZero = ExtendedPoint{feZero, feOne, feOne, feZero} + + epBase = ExtendedPoint{ + FieldElement{-41032219, -27199451, -7502359, -2800332, -50176896, + -33336453, -33570123, -31949908, -53948439, -29257844}, + FieldElement{20163995, 28827709, 65616271, 30544542, 24400674, + 29683035, 27175815, 26206403, 10372291, 5663137}, + feOne, + FieldElement{38281802, 6116118, 27349572, 33310069, 58473857, + 22289538, 47757517, 20140834, 50497352, 6414979}, + } +) + +// Sets fe to -a. Returns fe. +func (fe *FieldElement) Neg(a *FieldElement) *FieldElement { + fe[0] = -a[0] + fe[1] = -a[1] + fe[2] = -a[2] + fe[3] = -a[3] + fe[4] = -a[4] + fe[5] = -a[5] + fe[6] = -a[6] + fe[7] = -a[7] + fe[8] = -a[8] + fe[9] = -a[9] + return fe +} + +// Sets fe to a + b without normalizing. Returns fe. +func (fe *FieldElement) add(a, b *FieldElement) *FieldElement { + fe[0] = a[0] + b[0] + fe[1] = a[1] + b[1] + fe[2] = a[2] + b[2] + fe[3] = a[3] + b[3] + fe[4] = a[4] + b[4] + fe[5] = a[5] + b[5] + fe[6] = a[6] + b[6] + fe[7] = a[7] + b[7] + fe[8] = a[8] + b[8] + fe[9] = a[9] + b[9] + return fe +} + +// Sets fe to a - b without normalizing. Returns fe. +func (fe *FieldElement) sub(a, b *FieldElement) *FieldElement { + fe[0] = a[0] - b[0] + fe[1] = a[1] - b[1] + fe[2] = a[2] - b[2] + fe[3] = a[3] - b[3] + fe[4] = a[4] - b[4] + fe[5] = a[5] - b[5] + fe[6] = a[6] - b[6] + fe[7] = a[7] - b[7] + fe[8] = a[8] - b[8] + fe[9] = a[9] - b[9] + return fe +} + +// Interprets a 3-byte unsigned little endian byte-slice as int64 +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +// Interprets a 4-byte unsigned little endian byte-slice as int64 +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +// Reduce the even coefficients to below 1.01*2^25 and the odd coefficients +// to below 1.01*2^24. Returns fe. +func (fe *FieldElement) normalize() *FieldElement { + return fe.setReduced( + int64(fe[0]), int64(fe[1]), int64(fe[2]), int64(fe[3]), int64(fe[4]), + int64(fe[5]), int64(fe[6]), int64(fe[7]), int64(fe[8]), int64(fe[9])) +} + +// Set fe to h0 + h1*2^26 + h2*2^51 + ... + h9*2^230. Requires a little +// headroom in the inputs to store the carries. Returns fe. +func (fe *FieldElement) setReduced( + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) *FieldElement { + var c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 int64 + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + + c1 = (h1 + (1 << 24)) >> 25 + h2 += c1 + h1 -= c1 << 25 + c5 = (h5 + (1 << 24)) >> 25 + h6 += c5 + h5 -= c5 << 25 + + c2 = (h2 + (1 << 25)) >> 26 + h3 += c2 + h2 -= c2 << 26 + c6 = (h6 + (1 << 25)) >> 26 + h7 += c6 + h6 -= c6 << 26 + + c3 = (h3 + (1 << 24)) >> 25 + h4 += c3 + h3 -= c3 << 25 + c7 = (h7 + (1 << 24)) >> 25 + h8 += c7 + h7 -= c7 << 25 + + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + c8 = (h8 + (1 << 25)) >> 26 + h9 += c8 + h8 -= c8 << 26 + + c9 = (h9 + (1 << 24)) >> 25 + h0 += c9 * 19 + h9 -= c9 << 25 + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + + fe[0] = int32(h0) + fe[1] = int32(h1) + fe[2] = int32(h2) + fe[3] = int32(h3) + fe[4] = int32(h4) + fe[5] = int32(h5) + fe[6] = int32(h6) + fe[7] = int32(h7) + fe[8] = int32(h8) + fe[9] = int32(h9) + + return fe +} + +// Set fe to a if b == 1. Requires b to be either 0 or 1. +func (fe *FieldElement) ConditionalSet(a *FieldElement, b int32) { + b = -b // b == 0b11111111111111111111111111111111 or 0. + fe[0] ^= b & (fe[0] ^ a[0]) + fe[1] ^= b & (fe[1] ^ a[1]) + fe[2] ^= b & (fe[2] ^ a[2]) + fe[3] ^= b & (fe[3] ^ a[3]) + fe[4] ^= b & (fe[4] ^ a[4]) + fe[5] ^= b & (fe[5] ^ a[5]) + fe[6] ^= b & (fe[6] ^ a[6]) + fe[7] ^= b & (fe[7] ^ a[7]) + fe[8] ^= b & (fe[8] ^ a[8]) + fe[9] ^= b & (fe[9] ^ a[9]) +} + +// Write fe to s in little endian. Returns fe. +func (fe *FieldElement) BytesInto(s *[32]byte) *FieldElement { + var carry [10]int32 + + q := (19*fe[9] + (1 << 24)) >> 25 + q = (fe[0] + q) >> 26 + q = (fe[1] + q) >> 25 + q = (fe[2] + q) >> 26 + q = (fe[3] + q) >> 25 + q = (fe[4] + q) >> 26 + q = (fe[5] + q) >> 25 + q = (fe[6] + q) >> 26 + q = (fe[7] + q) >> 25 + q = (fe[8] + q) >> 26 + q = (fe[9] + q) >> 25 + + fe[0] += 19 * q + + carry[0] = fe[0] >> 26 + fe[1] += carry[0] + fe[0] -= carry[0] << 26 + carry[1] = fe[1] >> 25 + fe[2] += carry[1] + fe[1] -= carry[1] << 25 + carry[2] = fe[2] >> 26 + fe[3] += carry[2] + fe[2] -= carry[2] << 26 + carry[3] = fe[3] >> 25 + fe[4] += carry[3] + fe[3] -= carry[3] << 25 + carry[4] = fe[4] >> 26 + fe[5] += carry[4] + fe[4] -= carry[4] << 26 + carry[5] = fe[5] >> 25 + fe[6] += carry[5] + fe[5] -= carry[5] << 25 + carry[6] = fe[6] >> 26 + fe[7] += carry[6] + fe[6] -= carry[6] << 26 + carry[7] = fe[7] >> 25 + fe[8] += carry[7] + fe[7] -= carry[7] << 25 + carry[8] = fe[8] >> 26 + fe[9] += carry[8] + fe[8] -= carry[8] << 26 + carry[9] = fe[9] >> 25 + fe[9] -= carry[9] << 25 + + s[0] = byte(fe[0] >> 0) + s[1] = byte(fe[0] >> 8) + s[2] = byte(fe[0] >> 16) + s[3] = byte((fe[0] >> 24) | (fe[1] << 2)) + s[4] = byte(fe[1] >> 6) + s[5] = byte(fe[1] >> 14) + s[6] = byte((fe[1] >> 22) | (fe[2] << 3)) + s[7] = byte(fe[2] >> 5) + s[8] = byte(fe[2] >> 13) + s[9] = byte((fe[2] >> 21) | (fe[3] << 5)) + s[10] = byte(fe[3] >> 3) + s[11] = byte(fe[3] >> 11) + s[12] = byte((fe[3] >> 19) | (fe[4] << 6)) + s[13] = byte(fe[4] >> 2) + s[14] = byte(fe[4] >> 10) + s[15] = byte(fe[4] >> 18) + s[16] = byte(fe[5] >> 0) + s[17] = byte(fe[5] >> 8) + s[18] = byte(fe[5] >> 16) + s[19] = byte((fe[5] >> 24) | (fe[6] << 1)) + s[20] = byte(fe[6] >> 7) + s[21] = byte(fe[6] >> 15) + s[22] = byte((fe[6] >> 23) | (fe[7] << 3)) + s[23] = byte(fe[7] >> 5) + s[24] = byte(fe[7] >> 13) + s[25] = byte((fe[7] >> 21) | (fe[8] << 4)) + s[26] = byte(fe[8] >> 4) + s[27] = byte(fe[8] >> 12) + s[28] = byte((fe[8] >> 20) | (fe[9] << 6)) + s[29] = byte(fe[9] >> 2) + s[30] = byte(fe[9] >> 10) + s[31] = byte(fe[9] >> 18) + return fe +} + +// Sets fe to the little endian number encoded in buf modulo 2^255-19. +// Ignores the highest bit in buf. Returns fe. +func (fe *FieldElement) SetBytes(buf *[32]byte) *FieldElement { + return fe.setReduced( + load4(buf[:]), + load3(buf[4:])<<6, + load3(buf[7:])<<5, + load3(buf[10:])<<3, + load3(buf[13:])<<2, + load4(buf[16:]), + load3(buf[20:])<<7, + load3(buf[23:])<<5, + load3(buf[26:])<<4, + (load3(buf[29:])&8388607)<<2, + ) +} + +// Sets fe to a * b. Returns fe. +func (fe *FieldElement) Mul(a, b *FieldElement) *FieldElement { + a0 := int64(a[0]) + a1 := int64(a[1]) + a2 := int64(a[2]) + a3 := int64(a[3]) + a4 := int64(a[4]) + a5 := int64(a[5]) + a6 := int64(a[6]) + a7 := int64(a[7]) + a8 := int64(a[8]) + a9 := int64(a[9]) + + a1_2 := int64(2 * a[1]) + a3_2 := int64(2 * a[3]) + a5_2 := int64(2 * a[5]) + a7_2 := int64(2 * a[7]) + a9_2 := int64(2 * a[9]) + + b0 := int64(b[0]) + b1 := int64(b[1]) + b2 := int64(b[2]) + b3 := int64(b[3]) + b4 := int64(b[4]) + b5 := int64(b[5]) + b6 := int64(b[6]) + b7 := int64(b[7]) + b8 := int64(b[8]) + b9 := int64(b[9]) + + b1_19 := int64(19 * b[1]) + b2_19 := int64(19 * b[2]) + b3_19 := int64(19 * b[3]) + b4_19 := int64(19 * b[4]) + b5_19 := int64(19 * b[5]) + b6_19 := int64(19 * b[6]) + b7_19 := int64(19 * b[7]) + b8_19 := int64(19 * b[8]) + b9_19 := int64(19 * b[9]) + + h0 := a0*b0 + a1_2*b9_19 + a2*b8_19 + a3_2*b7_19 + a4*b6_19 + a5_2*b5_19 + a6*b4_19 + a7_2*b3_19 + a8*b2_19 + a9_2*b1_19 + h1 := a0*b1 + a1*b0 + a2*b9_19 + a3*b8_19 + a4*b7_19 + a5*b6_19 + a6*b5_19 + a7*b4_19 + a8*b3_19 + a9*b2_19 + h2 := a0*b2 + a1_2*b1 + a2*b0 + a3_2*b9_19 + a4*b8_19 + a5_2*b7_19 + a6*b6_19 + a7_2*b5_19 + a8*b4_19 + a9_2*b3_19 + h3 := a0*b3 + a1*b2 + a2*b1 + a3*b0 + a4*b9_19 + a5*b8_19 + a6*b7_19 + a7*b6_19 + a8*b5_19 + a9*b4_19 + h4 := a0*b4 + a1_2*b3 + a2*b2 + a3_2*b1 + a4*b0 + a5_2*b9_19 + a6*b8_19 + a7_2*b7_19 + a8*b6_19 + a9_2*b5_19 + h5 := a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0 + a6*b9_19 + a7*b8_19 + a8*b7_19 + a9*b6_19 + h6 := a0*b6 + a1_2*b5 + a2*b4 + a3_2*b3 + a4*b2 + a5_2*b1 + a6*b0 + a7_2*b9_19 + a8*b8_19 + a9_2*b7_19 + h7 := a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0 + a8*b9_19 + a9*b8_19 + h8 := a0*b8 + a1_2*b7 + a2*b6 + a3_2*b5 + a4*b4 + a5_2*b3 + a6*b2 + a7_2*b1 + a8*b0 + a9_2*b9_19 + h9 := a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0 + + return fe.setReduced(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// Returns the unnormalized coefficients of fe^2. +func (fe *FieldElement) square() (h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { + f0 := int64(fe[0]) + f1 := int64(fe[1]) + f2 := int64(fe[2]) + f3 := int64(fe[3]) + f4 := int64(fe[4]) + f5 := int64(fe[5]) + f6 := int64(fe[6]) + f7 := int64(fe[7]) + f8 := int64(fe[8]) + f9 := int64(fe[9]) + f0_2 := int64(2 * fe[0]) + f1_2 := int64(2 * fe[1]) + f2_2 := int64(2 * fe[2]) + f3_2 := int64(2 * fe[3]) + f4_2 := int64(2 * fe[4]) + f5_2 := int64(2 * fe[5]) + f6_2 := int64(2 * fe[6]) + f7_2 := int64(2 * fe[7]) + f5_38 := 38 * f5 + f6_19 := 19 * f6 + f7_38 := 38 * f7 + f8_19 := 19 * f8 + f9_38 := 38 * f9 + + h0 = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38 + h1 = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19 + h2 = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19 + h3 = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38 + h4 = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38 + h5 = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19 + h6 = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19 + h7 = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38 + h8 = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38 + h9 = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5 + + return +} + +// Sets fe to a^2. Returns fe. +func (fe *FieldElement) Square(a *FieldElement) *FieldElement { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := a.square() + return fe.setReduced(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// Sets fe to 2 * a^2. Returns fe. +func (fe *FieldElement) DoubledSquare(a *FieldElement) *FieldElement { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := a.square() + h0 += h0 + h1 += h1 + h2 += h2 + h3 += h3 + h4 += h4 + h5 += h5 + h6 += h6 + h7 += h7 + h8 += h8 + h9 += h9 + return fe.setReduced(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_mul64.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_mul64.go new file mode 100644 index 0000000000..045d485078 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_mul64.go @@ -0,0 +1,296 @@ +// +build go1.13,!forcegeneric + +package edwards25519 + +import ( + "math/bits" +) + +// Sets fe to a * b. Returns fe. +func (fe *FieldElement) Mul(a, b *FieldElement) *FieldElement { + a0 := a[0] + a1 := a[1] + a2 := a[2] + a3 := a[3] + a4 := a[4] + b0 := b[0] + b1 := b[1] + b2 := b[2] + b3 := b[3] + b4 := b[4] + b1_19 := b1 * 19 + b2_19 := b2 * 19 + b3_19 := b3 * 19 + b4_19 := b4 * 19 + + var carry, h, l uint64 + + // TODO make sure we only use bits.Add64 if it's constant-time + c0h, c0l := bits.Mul64(b0, a0) + h, l = bits.Mul64(b1_19, a4) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + h, l = bits.Mul64(b2_19, a3) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + h, l = bits.Mul64(b3_19, a2) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + h, l = bits.Mul64(b4_19, a1) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + + c1h, c1l := bits.Mul64(b0, a1) + h, l = bits.Mul64(b1, a0) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + h, l = bits.Mul64(b2_19, a4) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + h, l = bits.Mul64(b3_19, a3) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + h, l = bits.Mul64(b4_19, a2) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + + c1l, carry = bits.Add64((c0l>>51)|(c0h<<13), c1l, 0) + c1h, _ = bits.Add64(c1h, 0, carry) + c0l &= 0x7ffffffffffff + + c2h, c2l := bits.Mul64(b0, a2) + h, l = bits.Mul64(b1, a1) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + h, l = bits.Mul64(b2, a0) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + h, l = bits.Mul64(b3_19, a4) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + h, l = bits.Mul64(b4_19, a3) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + + c2l, carry = bits.Add64((c1l>>51)|(c1h<<13), c2l, 0) + c2h, _ = bits.Add64(c2h, 0, carry) + c1l &= 0x7ffffffffffff + + c3h, c3l := bits.Mul64(b0, a3) + h, l = bits.Mul64(b1, a2) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + h, l = bits.Mul64(b2, a1) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + h, l = bits.Mul64(b3, a0) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + h, l = bits.Mul64(b4_19, a4) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + + c3l, carry = bits.Add64((c2l>>51)|(c2h<<13), c3l, 0) + c3h, _ = bits.Add64(c3h, 0, carry) + c2l &= 0x7ffffffffffff + + c4h, c4l := bits.Mul64(b0, a4) + h, l = bits.Mul64(b1, a3) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + h, l = bits.Mul64(b2, a2) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + h, l = bits.Mul64(b3, a1) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + h, l = bits.Mul64(b4, a0) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + + c4l, carry = bits.Add64((c3l>>51)|(c3h<<13), c4l, 0) + c4h, _ = bits.Add64(c4h, 0, carry) + c3l &= 0x7ffffffffffff + + carry = ((c4l >> 51) | (c4h << 13)) + c4l &= 0x7ffffffffffff + c0l += carry * 19 + c1l += c0l >> 51 + c0l &= 0x7ffffffffffff + + fe[0] = c0l + fe[1] = c1l + fe[2] = c2l + fe[3] = c3l + fe[4] = c4l + + return fe +} + +// Sets fe to a^2. Returns fe. +func (fe *FieldElement) Square(a *FieldElement) *FieldElement { + a0 := a[0] + a1 := a[1] + a2 := a[2] + a3 := a[3] + a4 := a[4] + a4_38 := a4 * 38 + + var carry, h, l uint64 + + c0h, c0l := bits.Mul64(a0, a0) + h, l = bits.Mul64(a4*38, a1) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + h, l = bits.Mul64(a2*38, a3) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + + c1h, c1l := bits.Mul64(2*a0, a1) + h, l = bits.Mul64(a2, a4_38) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + h, l = bits.Mul64(a3*19, a3) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + + c1l, carry = bits.Add64((c0l>>51)|(c0h<<13), c1l, 0) + c1h, _ = bits.Add64(c1h, 0, carry) + c0l &= 0x7ffffffffffff + + c2h, c2l := bits.Mul64(a0, 2*a2) + h, l = bits.Mul64(a1, a1) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + h, l = bits.Mul64(a4_38, a3) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + + c2l, carry = bits.Add64((c1l>>51)|(c1h<<13), c2l, 0) + c2h, _ = bits.Add64(c2h, 0, carry) + c1l &= 0x7ffffffffffff + + c3h, c3l := bits.Mul64(a0, 2*a3) + h, l = bits.Mul64(2*a1, a2) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + h, l = bits.Mul64(a4*19, a4) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + + c3l, carry = bits.Add64((c2l>>51)|(c2h<<13), c3l, 0) + c3h, _ = bits.Add64(c3h, 0, carry) + c2l &= 0x7ffffffffffff + + c4h, c4l := bits.Mul64(a0, 2*a4) + h, l = bits.Mul64(a2, a2) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + h, l = bits.Mul64(a3, 2*a1) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + + c4l, carry = bits.Add64((c3l>>51)|(c3h<<13), c4l, 0) + c4h, _ = bits.Add64(c4h, 0, carry) + c3l &= 0x7ffffffffffff + + carry = ((c4l >> 51) | (c4h << 13)) + c0l += carry * 19 + c4l &= 0x7ffffffffffff + c1l += c0l >> 51 + c0l &= 0x7ffffffffffff + + fe[0] = c0l + fe[1] = c1l + fe[2] = c2l + fe[3] = c3l + fe[4] = c4l + + return fe +} + +// Sets fe to 2 * a^2. Returns fe. +func (fe *FieldElement) DoubledSquare(a *FieldElement) *FieldElement { + a0 := a[0] + a1 := a[1] + a2 := a[2] + a3 := a[3] + a4 := a[4] + a0_2 := a0 * 2 + a1_2 := a1 * 2 + a2_2 := a2 * 2 + a3_38 := a3 * 38 + a4_38 := a4 * 38 + + var carry, h, l uint64 + + c0h, c0l := bits.Mul64(a0, a0_2) + h, l = bits.Mul64(a4_38, a1_2) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + h, l = bits.Mul64(a2_2, a3_38) + c0l, carry = bits.Add64(c0l, l, 0) + c0h, _ = bits.Add64(c0h, h, carry) + + c1h, c1l := bits.Mul64(a0_2, a1_2) + h, l = bits.Mul64(a2_2, a4_38) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + h, l = bits.Mul64(a3_38, a3) + c1l, carry = bits.Add64(c1l, l, 0) + c1h, _ = bits.Add64(c1h, h, carry) + + c1l, carry = bits.Add64((c0l>>51)|(c0h<<13), c1l, 0) + c1h, _ = bits.Add64(c1h, 0, carry) + c0l &= 0x7ffffffffffff + + c2h, c2l := bits.Mul64(a0_2, a2_2) + h, l = bits.Mul64(a1_2, a1) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + h, l = bits.Mul64(a4_38, a3*2) + c2l, carry = bits.Add64(c2l, l, 0) + c2h, _ = bits.Add64(c2h, h, carry) + + c2l, carry = bits.Add64((c1l>>51)|(c1h<<13), c2l, 0) + c2h, _ = bits.Add64(c2h, 0, carry) + c1l &= 0x7ffffffffffff + + c3h, c3l := bits.Mul64(a0_2, 2*a3) + h, l = bits.Mul64(a1_2, a2_2) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + h, l = bits.Mul64(a4_38, a4) + c3l, carry = bits.Add64(c3l, l, 0) + c3h, _ = bits.Add64(c3h, h, carry) + + c3l, carry = bits.Add64((c2l>>51)|(c2h<<13), c3l, 0) + c3h, _ = bits.Add64(c3h, 0, carry) + c2l &= 0x7ffffffffffff + + c4h, c4l := bits.Mul64(a0_2, 2*a4) + h, l = bits.Mul64(a2_2, a2) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + h, l = bits.Mul64(2*a3, a1_2) + c4l, carry = bits.Add64(c4l, l, 0) + c4h, _ = bits.Add64(c4h, h, carry) + + c4l, carry = bits.Add64((c3l>>51)|(c3h<<13), c4l, 0) + c4h, _ = bits.Add64(c4h, 0, carry) + c3l &= 0x7ffffffffffff + + carry = ((c4l >> 51) | (c4h << 13)) + c0l += carry * 19 + c4l &= 0x7ffffffffffff + c1l += c0l >> 51 + c0l &= 0x7ffffffffffff + + fe[0] = c0l + fe[1] = c1l + fe[2] = c2l + fe[3] = c3l + fe[4] = c4l + + return fe +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_radix51.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_radix51.go new file mode 100644 index 0000000000..29f9095a64 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/field_radix51.go @@ -0,0 +1,278 @@ +// +build amd64,!forcegeneric go1.13,!forcegeneric + +package edwards25519 + +// Element of the field GF(2^255 - 19) over which the elliptic +// curve Edwards25519 is defined. +type FieldElement [5]uint64 + +var ( + feZero FieldElement + feOne = FieldElement{1, 0, 0, 0, 0} + feMinusOne = FieldElement{2251799813685228, 2251799813685247, + 2251799813685247, 2251799813685247, 2251799813685247} + + // sqrt(-1) + feI = FieldElement{ + 1718705420411056, 234908883556509, 2233514472574048, + 2117202627021982, 765476049583133, + } + + // -sqrt(-1) + feMinusI = FieldElement{ + 533094393274173, 2016890930128738, 18285341111199, + 134597186663265, 1486323764102114, + } + + // parameter d of Edwards25519 + feD = FieldElement{ + 929955233495203, 466365720129213, 1662059464998953, + 2033849074728123, 1442794654840575, + } + + // double feD + fe2D = FieldElement{ + 1859910466990425, 932731440258426, 1072319116312658, + 1815898335770999, 633789495995903, + } + + // 1 / sqrt(-1-d) + feInvSqrtMinusDMinusOne = FieldElement{ + 1972891073822467, 1430154612583622, 2243686579258279, + 473840635492096, 133279003116800, + } + + // 2 / sqrt(-1-d) + feDoubleInvSqrtMinusDMinusOne = FieldElement{ + 1693982333959686, 608509411481997, 2235573344831311, + 947681270984193, 266558006233600, + } + + // 2i / sqrt(-1-d) + feDoubleIInvSqrtMinusDMinusOne = FieldElement{ + 1608655899704280, 1999971613377227, 49908634785720, + 1873700692181652, 353702208628067, + } + + // (d-1)^2 + feDMinusOneSquared = FieldElement{ + 1507062230895904, 1572317787530805, 683053064812840, + 317374165784489, 1572899562415810, + } + + // 1 - d^2 + feOneMinusDSquared = FieldElement{ + 1136626929484150, 1998550399581263, 496427632559748, + 118527312129759, 45110755273534, + } + + // (d+1)/(d-1) + feDp1OverDm1 = FieldElement{ + 2159851467815724, 1752228607624431, 1825604053920671, + 1212587319275468, 253422448836237, + } + + // sqrt(i*d) + feSqrtID = FieldElement{ + 2298852427963285, 3837146560810661, 4413131899466403, + 3883177008057528, 2352084440532925, + } + + // 1/sqrt(d+1) + feInvSqrt1pD = FieldElement{ + 321571956990465, 1251814006996634, 2226845496292387, + 189049560751797, 2074948709371214, + } + + epZero = ExtendedPoint{feZero, feOne, feOne, feZero} + + epBase = ExtendedPoint{ + FieldElement{2678275328304575, 4315672520525287, 2266428086574206, + 2359477563015859, 2540138899492839}, + FieldElement{1934594822876571, 2049809580636559, 1991994783322914, + 1758681962032007, 380046701118659}, + feOne, + FieldElement{410445769351754, 2235400917701188, 1495825632738689, + 1351628537510093, 430502003771208}, + } +) + +// Neg sets fe to -a. Returns fe. +func (fe *FieldElement) Neg(a *FieldElement) *FieldElement { + var t FieldElement + t = *a + + t[1] += t[0] >> 51 + t[0] = t[0] & 0x7ffffffffffff + t[2] += t[1] >> 51 + t[1] = t[1] & 0x7ffffffffffff + t[3] += t[2] >> 51 + t[2] = t[2] & 0x7ffffffffffff + t[4] += t[3] >> 51 + t[3] = t[3] & 0x7ffffffffffff + t[0] += (t[4] >> 51) * 19 + t[4] = t[4] & 0x7ffffffffffff + + fe[0] = 0xfffffffffffda - t[0] + fe[1] = 0xffffffffffffe - t[1] + fe[2] = 0xffffffffffffe - t[2] + fe[3] = 0xffffffffffffe - t[3] + fe[4] = 0xffffffffffffe - t[4] + + return fe +} + +// Sets fe to a-b. Returns fe. +func (fe *FieldElement) sub(a, b *FieldElement) *FieldElement { + var t FieldElement + t = *b + + t[1] += t[0] >> 51 + t[0] = t[0] & 0x7ffffffffffff + t[2] += t[1] >> 51 + t[1] = t[1] & 0x7ffffffffffff + t[3] += t[2] >> 51 + t[2] = t[2] & 0x7ffffffffffff + t[4] += t[3] >> 51 + t[3] = t[3] & 0x7ffffffffffff + t[0] += (t[4] >> 51) * 19 + t[4] = t[4] & 0x7ffffffffffff + + fe[0] = (a[0] + 0xfffffffffffda) - t[0] + fe[1] = (a[1] + 0xffffffffffffe) - t[1] + fe[2] = (a[2] + 0xffffffffffffe) - t[2] + fe[3] = (a[3] + 0xffffffffffffe) - t[3] + fe[4] = (a[4] + 0xffffffffffffe) - t[4] + + return fe +} + +// Sets fe to a + b without normalizing. Returns fe. +func (fe *FieldElement) add(a, b *FieldElement) *FieldElement { + fe[0] = a[0] + b[0] + fe[1] = a[1] + b[1] + fe[2] = a[2] + b[2] + fe[3] = a[3] + b[3] + fe[4] = a[4] + b[4] + return fe +} + +// Reduce the even coefficients. Returns fe. +func (fe *FieldElement) normalize() *FieldElement { + return fe.setReduced(fe) +} + +// Set fe to a reduced version of a. Returns fe. +func (fe *FieldElement) setReduced(a *FieldElement) *FieldElement { + *fe = *a + + fe[1] += fe[0] >> 51 + fe[0] = fe[0] & 0x7ffffffffffff + fe[2] += fe[1] >> 51 + fe[1] = fe[1] & 0x7ffffffffffff + fe[3] += fe[2] >> 51 + fe[2] = fe[2] & 0x7ffffffffffff + fe[4] += fe[3] >> 51 + fe[3] = fe[3] & 0x7ffffffffffff + fe[0] += (fe[4] >> 51) * 19 + fe[4] = fe[4] & 0x7ffffffffffff + + c := (fe[0] + 19) >> 51 + c = (fe[1] + c) >> 51 + c = (fe[2] + c) >> 51 + c = (fe[3] + c) >> 51 + c = (fe[4] + c) >> 51 + + fe[0] += 19 * c + + fe[1] += fe[0] >> 51 + fe[0] = fe[0] & 0x7ffffffffffff + fe[2] += fe[1] >> 51 + fe[1] = fe[1] & 0x7ffffffffffff + fe[3] += fe[2] >> 51 + fe[2] = fe[2] & 0x7ffffffffffff + fe[4] += fe[3] >> 51 + fe[3] = fe[3] & 0x7ffffffffffff + fe[4] = fe[4] & 0x7ffffffffffff + + return fe +} + +// Set fe to a if b == 1. Requires b to be either 0 or 1. +func (fe *FieldElement) ConditionalSet(a *FieldElement, b int32) { + b2 := uint64(1-b) - 1 + fe[0] ^= b2 & (fe[0] ^ a[0]) + fe[1] ^= b2 & (fe[1] ^ a[1]) + fe[2] ^= b2 & (fe[2] ^ a[2]) + fe[3] ^= b2 & (fe[3] ^ a[3]) + fe[4] ^= b2 & (fe[4] ^ a[4]) +} + +// Write fe to s in little endian. Returns fe. +func (fe *FieldElement) BytesInto(s *[32]byte) *FieldElement { + var t FieldElement + t.setReduced(fe) + + s[0] = byte(t[0] & 0xff) + s[1] = byte((t[0] >> 8) & 0xff) + s[2] = byte((t[0] >> 16) & 0xff) + s[3] = byte((t[0] >> 24) & 0xff) + s[4] = byte((t[0] >> 32) & 0xff) + s[5] = byte((t[0] >> 40) & 0xff) + s[6] = byte((t[0] >> 48)) + s[6] ^= byte((t[1] << 3) & 0xf8) + s[7] = byte((t[1] >> 5) & 0xff) + s[8] = byte((t[1] >> 13) & 0xff) + s[9] = byte((t[1] >> 21) & 0xff) + s[10] = byte((t[1] >> 29) & 0xff) + s[11] = byte((t[1] >> 37) & 0xff) + s[12] = byte((t[1] >> 45)) + s[12] ^= byte((t[2] << 6) & 0xc0) + s[13] = byte((t[2] >> 2) & 0xff) + s[14] = byte((t[2] >> 10) & 0xff) + s[15] = byte((t[2] >> 18) & 0xff) + s[16] = byte((t[2] >> 26) & 0xff) + s[17] = byte((t[2] >> 34) & 0xff) + s[18] = byte((t[2] >> 42) & 0xff) + s[19] = byte((t[2] >> 50)) + s[19] ^= byte((t[3] << 1) & 0xfe) + s[20] = byte((t[3] >> 7) & 0xff) + s[21] = byte((t[3] >> 15) & 0xff) + s[22] = byte((t[3] >> 23) & 0xff) + s[23] = byte((t[3] >> 31) & 0xff) + s[24] = byte((t[3] >> 39) & 0xff) + s[25] = byte((t[3] >> 47)) + s[25] ^= byte((t[4] << 4) & 0xf0) + s[26] = byte((t[4] >> 4) & 0xff) + s[27] = byte((t[4] >> 12) & 0xff) + s[28] = byte((t[4] >> 20) & 0xff) + s[29] = byte((t[4] >> 28) & 0xff) + s[30] = byte((t[4] >> 36) & 0xff) + s[31] = byte((t[4] >> 44)) + return fe +} + +// Sets fe to the little endian number encoded in buf modulo 2^255-19. +// Ignores the highest bit in buf. Returns fe. +func (fe *FieldElement) SetBytes(buf *[32]byte) *FieldElement { + fe[0] = (uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | + (uint64(buf[3]) << 24) | (uint64(buf[4]) << 32) | + (uint64(buf[5]) << 40) | (uint64(buf[6]&7) << 48)) + fe[1] = ((uint64(buf[6]) >> 3) | (uint64(buf[7]) << 5) | + (uint64(buf[8]) << 13) | (uint64(buf[9]) << 21) | + (uint64(buf[10]) << 29) | (uint64(buf[11]) << 37) | + (uint64(buf[12]&63) << 45)) + fe[2] = ((uint64(buf[12]) >> 6) | (uint64(buf[13]) << 2) | + (uint64(buf[14]) << 10) | (uint64(buf[15]) << 18) | + (uint64(buf[16]) << 26) | (uint64(buf[17]) << 34) | + (uint64(buf[18]) << 42) | (uint64(buf[19]&1) << 50)) + fe[3] = ((uint64(buf[19]) >> 1) | (uint64(buf[20]) << 7) | + (uint64(buf[21]) << 15) | (uint64(buf[22]) << 23) | + (uint64(buf[23]) << 31) | (uint64(buf[24]) << 39) | + (uint64(buf[25]&15) << 47)) + fe[4] = ((uint64(buf[25]) >> 4) | (uint64(buf[26]) << 4) | + (uint64(buf[27]) << 12) | (uint64(buf[28]) << 20) | + (uint64(buf[29]) << 28) | (uint64(buf[30]) << 36) | + (uint64(buf[31]&127) << 44)) + return fe +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/table.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table.go new file mode 100644 index 0000000000..09e431a2ba --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table.go @@ -0,0 +1,217 @@ +package edwards25519 + +type NielsPoint struct { + YPlusX, YMinusX, XY2D FieldElement +} + +// Precomputed scalar multiplication table +type ScalarMultTable [32][8]NielsPoint + +// Set p to zero, the neutral element. Return p. +func (p *NielsPoint) SetZero() *NielsPoint { + p.YMinusX.SetOne() + p.YPlusX.SetOne() + p.XY2D.SetZero() + return p +} + +// Set p to q. Returns p. +func (p *NielsPoint) Set(q *NielsPoint) *NielsPoint { + p.YPlusX.Set(&q.YPlusX) + p.YMinusX.Set(&q.YMinusX) + p.XY2D.Set(&q.XY2D) + return p +} + +// Set p to q if b == 1. Assumes b is 0 or 1. Returns p. +func (p *NielsPoint) ConditionalSet(q *NielsPoint, b int32) *NielsPoint { + p.YPlusX.ConditionalSet(&q.YPlusX, b) + p.YMinusX.ConditionalSet(&q.YMinusX, b) + p.XY2D.ConditionalSet(&q.XY2D, b) + return p +} + +// Set p to -q. Returns p. +func (p *NielsPoint) Neg(q *NielsPoint) *NielsPoint { + p.YMinusX.Set(&q.YPlusX) + p.YPlusX.Set(&q.YMinusX) + p.XY2D.Neg(&q.XY2D) + return p +} + +// Sets p to q+r. Returns p. +func (p *CompletedPoint) AddExtendedNiels(q *ExtendedPoint, r *NielsPoint) *CompletedPoint { + var t0 FieldElement + + p.X.add(&q.Y, &q.X) + p.Y.sub(&q.Y, &q.X) + p.Z.Mul(&p.X, &r.YPlusX) + p.Y.Mul(&p.Y, &r.YMinusX) + p.T.Mul(&r.XY2D, &q.T) + t0.add(&q.Z, &q.Z) + p.X.sub(&p.Z, &p.Y) + p.Y.add(&p.Z, &p.Y) + p.Z.add(&t0, &p.T) + p.T.sub(&t0, &p.T) + return p +} + +// Set p to q-r. Returns p. +func (p *CompletedPoint) SubExtendedNiels(q *ExtendedPoint, r *NielsPoint) *CompletedPoint { + var t0 FieldElement + + p.X.add(&q.Y, &q.X) + p.Y.sub(&q.Y, &q.X) + p.Z.Mul(&p.X, &r.YMinusX) + p.Y.Mul(&p.Y, &r.YPlusX) + p.T.Mul(&r.XY2D, &q.T) + t0.add(&q.Z, &q.Z) + p.X.sub(&p.Z, &p.Y) + p.Y.add(&p.Z, &p.Y) + p.Z.sub(&t0, &p.T) + p.T.add(&t0, &p.T) + return p +} + +// Sets p to q. Returns p. +func (p *NielsPoint) SetExtended(q *ExtendedPoint) *NielsPoint { + var x, y, zInv FieldElement + zInv.Inverse(&q.Z) + x.Mul(&q.X, &zInv) + y.Mul(&q.Y, &zInv) + p.YPlusX.Add(&y, &x) + p.YMinusX.Sub(&y, &x) + p.XY2D.Mul(&x, &y) + p.XY2D.Add(&p.XY2D, &p.XY2D) + p.XY2D.Mul(&p.XY2D, &feD) + return p +} + +// Fill the table t with data for the point p. +func (t *ScalarMultTable) Compute(p *ExtendedPoint) { + var c, cp ExtendedPoint + var c_pp ProjectivePoint + var c_cp CompletedPoint + cp.Set(p) + for i := 0; i < 32; i++ { + c.SetZero() + for v := 0; v < 8; v++ { + c.Add(&c, &cp) + t[i][v].SetExtended(&c) + } + c_cp.DoubleExtended(&c) + c_pp.SetCompleted(&c_cp) + c_cp.DoubleProjective(&c_pp) + c_pp.SetCompleted(&c_cp) + c_cp.DoubleProjective(&c_pp) + c_pp.SetCompleted(&c_cp) + c_cp.DoubleProjective(&c_pp) + c_pp.SetCompleted(&c_cp) + c_cp.DoubleProjective(&c_pp) + cp.SetCompleted(&c_cp) + } +} + +// Compute 4-bit signed window for the scalar s +func computeScalarWindow4(s *[32]byte, w *[64]int8) { + for i := 0; i < 32; i++ { + w[2*i] = int8(s[i] & 15) + w[2*i+1] = int8((s[i] >> 4) & 15) + } + carry := int8(0) + for i := 0; i < 63; i++ { + w[i] += carry + carry = (w[i] + 8) >> 4 + w[i] -= carry << 4 + } + w[63] += carry +} + +// Set p to s * q, where t was computed for q using t.Compute(q). +func (t *ScalarMultTable) ScalarMult(p *ExtendedPoint, s *[32]byte) { + var w [64]int8 + computeScalarWindow4(s, &w) + + p.SetZero() + var np NielsPoint + var cp CompletedPoint + var pp ProjectivePoint + + for i := int32(0); i < 32; i++ { + t.selectPoint(&np, i, int32(w[2*i+1])) + cp.AddExtendedNiels(p, &np) + p.SetCompleted(&cp) + } + + cp.DoubleExtended(p) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + p.SetCompleted(&cp) + + for i := int32(0); i < 32; i++ { + t.selectPoint(&np, i, int32(w[2*i])) + cp.AddExtendedNiels(p, &np) + p.SetCompleted(&cp) + } +} + +func (t *ScalarMultTable) VarTimeScalarMult(p *ExtendedPoint, s *[32]byte) { + var w [64]int8 + computeScalarWindow4(s, &w) + + p.SetZero() + var np NielsPoint + var cp CompletedPoint + var pp ProjectivePoint + + for i := int32(0); i < 32; i++ { + if t.varTimeSelectPoint(&np, i, int32(w[2*i+1])) { + cp.AddExtendedNiels(p, &np) + p.SetCompleted(&cp) + } + } + + cp.DoubleExtended(p) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + p.SetCompleted(&cp) + + for i := int32(0); i < 32; i++ { + if t.varTimeSelectPoint(&np, i, int32(w[2*i])) { + cp.AddExtendedNiels(p, &np) + p.SetCompleted(&cp) + } + } +} + +func (t *ScalarMultTable) selectPoint(p *NielsPoint, pos int32, b int32) { + bNegative := negative(b) + bAbs := b - (((-bNegative) & b) << 1) + p.SetZero() + for i := int32(0); i < 8; i++ { + p.ConditionalSet(&t[pos][i], equal30(bAbs, i+1)) + } + var negP NielsPoint + negP.Neg(p) + p.ConditionalSet(&negP, bNegative) +} + +func (t *ScalarMultTable) varTimeSelectPoint(p *NielsPoint, pos int32, b int32) bool { + if b == 0 { + return false + } + if b < 0 { + p.Neg(&t[pos][-b-1]) + } else { + p.Set(&t[pos][b-1]) + } + return true +} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_generic.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_generic.go new file mode 100644 index 0000000000..00aee1724b --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_generic.go @@ -0,0 +1,1795 @@ +// +build !amd64,!go1.13 forcegeneric + +package edwards25519 + +var BaseScalarMultTable = ScalarMultTable{[8]NielsPoint{NielsPoint{YPlusX: FieldElement{-20868243, + 1628258, -8994952, -5810221, -25776221, -3653418, -6394308, -5743505, + 23532716, 9959724}, YMinusX: FieldElement{-5912631, + -11081703, 6009768, -209557, 7468707, -4089375, -6362924, -8952552, + -2788132, 1366550}, XY2D: FieldElement{8738181, -4489570, + -9688441, 14785194, -10184609, 12363380, -29287919, -11864899, + 24514362, 4438546}}, + NielsPoint{YPlusX: FieldElement{12815894, + 12976347, 21581243, -11784320, 25355658, 2750717, 11717903, 3814571, + 358445, 10211303}, YMinusX: FieldElement{21703237, + -6903825, -27185491, -6451973, 29577724, 9554005, 15616551, -11189268, + 26829678, 5319081}, XY2D: FieldElement{26966642, 11152617, + 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, + -15472047, -4166697}}, + NielsPoint{YPlusX: FieldElement{-33386987, + -12413499, -23610196, 3649136, 2210761, -15537909, 26511630, 2078608, + 26886373, -15609059}, YMinusX: FieldElement{24545969, + -3506838, -5277728, -12534841, 13008707, -2927197, 6206343, -3258065, + -16397082, 7100930}, XY2D: FieldElement{-30464156, + 5976125, 11779434, 15670865, -23220365, -15915852, -7512774, + -10017326, 17749093, 9920357}}, + NielsPoint{YPlusX: FieldElement{-17036878, + 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, + 15006023, 3284568, -6276540}, YMinusX: FieldElement{23599295, + -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, + 13059162, 10374397}, XY2D: FieldElement{7798556, 16710257, + 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, + -101325}}, + NielsPoint{YPlusX: FieldElement{-11928380, + -3963360, 27070730, -6703809, -6270217, 9853481, -7538109, -279533, + 19121671, 6982365}, YMinusX: FieldElement{-31493446, + 7202222, 6295441, 7646477, 12700127, 6760065, -16332637, -5336593, + 28935082, -12691219}, XY2D: FieldElement{-19563160, + -16186464, 29386857, -4097519, -10237984, 4348115, -28542350, + -13850243, 23678021, 15815942}}, + NielsPoint{YPlusX: FieldElement{15371964, + 12862754, -32573250, -4720197, 26436522, -5875511, 19188627, 15224819, + 9818940, 12085777}, YMinusX: FieldElement{8549212, + -109983, -15149363, -2178705, -22900618, -4543417, -3044240, 15689887, + -1762328, -14866737}, XY2D: FieldElement{-18199695, + -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, + 3959421, 27914454, 4383652}}, + NielsPoint{YPlusX: FieldElement{-32121264, + -6939727, -11004492, -14675536, 8474162, 2468373, -12281005, 1725003, + -26737328, -9116199}, YMinusX: FieldElement{403439, + -2794281, -28670699, -6746546, -20782317, -5907090, 19183506, + -3732089, -20017639, 240133}, XY2D: FieldElement{-28881845, + -14381568, -9657904, -3680757, 20181635, -7843316, 31400660, -1370708, + -29794553, 1409300}}, + NielsPoint{YPlusX: FieldElement{14499471, + -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, + -33154098, 2381726}, YMinusX: FieldElement{-7195431, + -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, + -32300832, 15351955}, XY2D: FieldElement{27431194, + 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, + 29551813, 10109425}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-13657040, + -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, + 10092783, -4764171}, YMinusX: FieldElement{27939166, + 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, + 12005538, -17810127, 12803510}, XY2D: FieldElement{17228999, + -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, + 18016357, 4397660}}, + NielsPoint{YPlusX: FieldElement{-10958843, + -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, + 14544525, -17477504, 982639}, YMinusX: FieldElement{29253598, + 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, + -21047696, 9934963}, XY2D: FieldElement{5793303, 16271923, + -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, + -30123922, -10897950}}, + NielsPoint{YPlusX: FieldElement{-27643952, + -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, + 4541697, -13338309, 5500568}, YMinusX: FieldElement{12650548, + -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, + 10874051, 13524335}, XY2D: FieldElement{25556948, + -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, + -22528059, 5376628}}, + NielsPoint{YPlusX: FieldElement{-26088264, + -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, + 4535768, 1569007}, YMinusX: FieldElement{-2255422, + 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, + 31848280, 12543772}, XY2D: FieldElement{-22028579, + 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, + 7718482, 14474653}}, + NielsPoint{YPlusX: FieldElement{2385315, + 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, + 24316168, -5253567}, YMinusX: FieldElement{13741529, + 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, + -13424532, -20729456, 8321686}, XY2D: FieldElement{21060490, + -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, + -9984458, 608372}}, + NielsPoint{YPlusX: FieldElement{-13672732, + -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, + 27229399, 23887}, YMinusX: FieldElement{-23244140, + -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, + -1633405, 16678954}, XY2D: FieldElement{-29500620, + 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, + -17169265, 4904953}}, + NielsPoint{YPlusX: FieldElement{24059557, + 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, + 2128236, -4326833}, YMinusX: FieldElement{-16981152, + 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, + -6882542, -2986532}, XY2D: FieldElement{-22630907, + 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, + 15736322, 4143876}}, + NielsPoint{YPlusX: FieldElement{2379352, + 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, + 23527084, -16458268}, YMinusX: FieldElement{33431127, + -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, + 4087881, -15188911, -14416214}, XY2D: FieldElement{1767683, + 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, + -4774191, -16323038}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{6721966, + 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, + -3949732, 7390890, 2759800}, YMinusX: FieldElement{4409041, + 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, + 1244380, -12919645}, XY2D: FieldElement{-4421239, + 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, + 15886429, 16489664}}, + NielsPoint{YPlusX: FieldElement{1996075, + 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, + -30606455, -712933}, YMinusX: FieldElement{-25307465, + 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, + -30836462, 5113182}, XY2D: FieldElement{-17770784, + 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, + -7336386, 13847711, 5387222}}, + NielsPoint{YPlusX: FieldElement{-18582163, + -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, + -19600662, 10370991}, YMinusX: FieldElement{20246567, + -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, + 32232924, 16763880}, XY2D: FieldElement{9648505, 10094563, + 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, + -16510092}}, + NielsPoint{YPlusX: FieldElement{-16160072, + 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, + -28774454, 366295}, YMinusX: FieldElement{19153450, + 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, + 719605, 11671788}, XY2D: FieldElement{8678025, 2694440, + -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, + -10195553}}, + NielsPoint{YPlusX: FieldElement{-15157904, + 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, + 6750977, -14521026}, YMinusX: FieldElement{11836410, + -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, + 8169720, 16220347}, XY2D: FieldElement{-18115838, + 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, + -5990708, -14166033}}, + NielsPoint{YPlusX: FieldElement{-23308498, + -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, + 2847284, 2655861, 1738395}, YMinusX: FieldElement{-27537433, + -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, + -19087449, -11005278}, XY2D: FieldElement{1533110, + 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, + 10478196, 8544890}}, + NielsPoint{YPlusX: FieldElement{32173121, + -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, + 17789017, -3395995}, YMinusX: FieldElement{-30552961, + -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, + 30460520, 1052596}, XY2D: FieldElement{-11614875, + 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, + 3179268, -9478891}}, + NielsPoint{YPlusX: FieldElement{31947069, + -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, + -16411740, 19072640, -9511060}, YMinusX: FieldElement{11685058, + 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, + 473099, 5040608}, XY2D: FieldElement{-20290863, 8198642, + -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, + -3131606}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{7881532, + 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, + -27868496, 11538389}, YMinusX: FieldElement{-19935666, + 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, + -5676054, 5797016}, XY2D: FieldElement{-11295600, + -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, + -2369172, -5877341}}, + NielsPoint{YPlusX: FieldElement{-22472376, + -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, + 15123619, 10811505}, YMinusX: FieldElement{14352098, + -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, + -28886779, -11974553}, XY2D: FieldElement{-28241164, + -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, + 4714547, -9600655}}, + NielsPoint{YPlusX: FieldElement{15200332, 8368572, + 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, + 12340220}, YMinusX: FieldElement{12876937, -10480056, + 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, + 9608631}, XY2D: FieldElement{-4143277, -12014408, + 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, + -8814099}}, + NielsPoint{YPlusX: FieldElement{26660628, + -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, + 20571223, 8420556}, YMinusX: FieldElement{14620715, + 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, + -21574435, -12476749}, XY2D: FieldElement{236881, + 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, + 8791136, 15069930}}, + NielsPoint{YPlusX: FieldElement{1276410, + -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, + 4874229, -30663140, -2331391}, YMinusX: FieldElement{5855666, + 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, + -33069337, 9234253}, XY2D: FieldElement{20590503, + -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, + 18979186, 13396066}}, + NielsPoint{YPlusX: FieldElement{24474287, 4968103, + 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, + 7021958}, YMinusX: FieldElement{-11566906, -6565505, + -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, + -21480480, 12868082}, XY2D: FieldElement{-28635013, + 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, + -12455797, -8089383}}, + NielsPoint{YPlusX: FieldElement{-30595528, + 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, + -15233648, 5540521}, YMinusX: FieldElement{-11630176, + -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, + -16128528, -14962807}, XY2D: FieldElement{23152971, + 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, + -11513277, -15205948}}, + NielsPoint{YPlusX: FieldElement{9770129, + 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, + -19179614, 5867134}, YMinusX: FieldElement{-32765025, + 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, + -29749703, -16108455}, XY2D: FieldElement{27461885, + -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, + -19526700, 7734629}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-8010264, + -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, + 18549497, 15302069}, YMinusX: FieldElement{-32658337, + -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, + -8872242, 8424746}, XY2D: FieldElement{24687205, 8613276, + -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, + -828919}}, + NielsPoint{YPlusX: FieldElement{11334899, + -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, + -5066034, 16498837}, YMinusX: FieldElement{8911542, + 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, + 6536641, 10543906}, XY2D: FieldElement{-28946384, + 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, + -27235709, 8876771}}, + NielsPoint{YPlusX: FieldElement{-25742899, + -12566864, -15649966, -846607, -33026686, -796288, -33481822, + 15824474, -604426, -9039817}, YMinusX: FieldElement{10330056, + 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, + 1657394, 3084098}, XY2D: FieldElement{10477963, -7470260, + 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, + -30233575, 15272409}}, + NielsPoint{YPlusX: FieldElement{-12288309, + 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, + -25014757, 1950504}, YMinusX: FieldElement{-26180358, + 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, + 15341279, 8373727}, XY2D: FieldElement{28685821, 7759505, + -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, + 15190420}}, + NielsPoint{YPlusX: FieldElement{-32932876, + 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, + 2742393, -26033313, -6875003}, YMinusX: FieldElement{-1580388, + -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, + -16247779, -12154742, 6048605}, XY2D: FieldElement{-30305315, + 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, + 11213262, 9168384}}, + NielsPoint{YPlusX: FieldElement{-26280513, + 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, + 20470157, -16398701}, YMinusX: FieldElement{-23136053, + 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, + 14461608, 14042978, 5230683}, XY2D: FieldElement{29969567, + -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, + -5933891, -12449708}}, + NielsPoint{YPlusX: FieldElement{-3144746, 8744661, + 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, + 15326563}, YMinusX: FieldElement{-19464629, 10110288, + -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, + -20514118, 9168260}, XY2D: FieldElement{-5353335, + 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, + 33087103, -9011387}}, + NielsPoint{YPlusX: FieldElement{-19443170, + -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, + -15000531, -5996870, 15664672}, YMinusX: FieldElement{23294591, + -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, + -2460356, 18151676, 13417686}, XY2D: FieldElement{-24722913, + -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, + 15271676, -15452665}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{11433042, + -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, + -6921301, -13440182}, YMinusX: FieldElement{-31436171, + 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, + 12215110, 12028277}, XY2D: FieldElement{14098400, + 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, + -16900089, -655628}}, + NielsPoint{YPlusX: FieldElement{-4026201, + -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, + 10154009, 23973261, -12684474}, + YMinusX: FieldElement{-26531820, -3695990, -1908898, + 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, + -10103539}, XY2D: FieldElement{-25479301, 10876443, + -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, + -837822}}, + NielsPoint{YPlusX: FieldElement{-10433389, + -14612966, 22229858, -3091047, -13191166, 776729, -17415375, + -12020462, 4725005, 14044970}, YMinusX: FieldElement{19268650, + -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, + -19522291, -16109756}, XY2D: FieldElement{-24864089, + 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, + 9282262, 10282508}}, + NielsPoint{YPlusX: FieldElement{-26205082, + 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, + 5542595, -10702683}, YMinusX: FieldElement{-10562541, + 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, + 6993761, -18093885, 10114655}, XY2D: FieldElement{-20107055, + -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, + 25953725, -106158}}, + NielsPoint{YPlusX: FieldElement{-4234397, + -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, + -3315279, 12831125}, YMinusX: FieldElement{-15998678, + 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, + 7381791, -2421839}, XY2D: FieldElement{-20902779, + 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, + -15362489, 12339664}}, + NielsPoint{YPlusX: FieldElement{27724736, 2291157, + 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, + 14856294}, YMinusX: FieldElement{-18866652, 8331043, + 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, + -9012899}, XY2D: FieldElement{-11423429, -5421590, + 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, + 9142070}}, + NielsPoint{YPlusX: FieldElement{3924129, + -15307516, -13817122, -10054960, 12291820, -668366, -27702774, + 9326384, -8237858, 4171294}, YMinusX: FieldElement{-15921940, + 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, + 345228, -5462949}, XY2D: FieldElement{-21327538, 13448259, + 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, + -13582083}}, + NielsPoint{YPlusX: FieldElement{31016211, + -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, + 3842657, 28012650, -16405420}, YMinusX: FieldElement{-5075835, + 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, + -8867157, 3507940}, XY2D: FieldElement{29439664, 3537914, + 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, + -9164929, 6580396}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-12185861, + -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, + -2095802, 9304567}, YMinusX: FieldElement{20714564, + -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, + 5289421, -477127}, XY2D: FieldElement{-16665533, + -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, + 26939669, -3752294}}, + NielsPoint{YPlusX: FieldElement{-12889898, + 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, + -3698806, 117887}, YMinusX: FieldElement{22263325, + -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, + -23319780, 541964}, XY2D: FieldElement{16259219, 3261970, + 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, + -13337066, -13552195}}, + NielsPoint{YPlusX: FieldElement{9378160, + -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, + -717351, 690426, 14876244}, YMinusX: FieldElement{24977353, + -314384, -8223969, -13465086, 28432343, -1176353, -13068804, + -12297348, -22380984, 6618999}, XY2D: FieldElement{-1538174, + 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, + -13817328, 32239829, -5652762}}, + NielsPoint{YPlusX: FieldElement{-18603066, + 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, + 32779359, 5095274}, YMinusX: FieldElement{-33008130, + -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, + 21639561, -2630236}, XY2D: FieldElement{-16400943, + -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, + 17874574, 558605}}, + NielsPoint{YPlusX: FieldElement{-13600129, + 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, + 2085892, 5119761}, YMinusX: FieldElement{-22205145, + -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, + -31999993, -5759884}, XY2D: FieldElement{-6845704, + 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, + -22351378, 12961482}}, + NielsPoint{YPlusX: FieldElement{-24492060, + -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, + -30194652, -5159638}, YMinusX: FieldElement{-11121496, + -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, + 7589640, 8945490}, XY2D: FieldElement{-32152748, 8917967, + 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, + -14456170}}, + NielsPoint{YPlusX: FieldElement{5019558, + -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, + -13289025, -6231896, -10280736}, + YMinusX: FieldElement{10853594, 10721687, 26480089, + 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124}, + XY2D: FieldElement{-17002408, 5906790, 221599, -6563147, + 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}}, + NielsPoint{YPlusX: FieldElement{8139927, + -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, + 28826358, -4123029}, YMinusX: FieldElement{6267086, + 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, + 13746021, -1742048}, XY2D: FieldElement{28584902, + 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, + 4771362, -8419958}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{24949256, + 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, + -12141695, 3569627, 11342593}, YMinusX: FieldElement{26514989, + 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, + 7325975, -14801071}, XY2D: FieldElement{-11618399, + -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, + -17646694, -8186692}}, + NielsPoint{YPlusX: FieldElement{11431204, + 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, + 9280358, -3973687}, YMinusX: FieldElement{-160783, + -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, + -11181622, -15545091, 4387441}, XY2D: FieldElement{-20799378, + 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, + 20617071, -7482001}}, + NielsPoint{YPlusX: FieldElement{-938825, + -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, + -11875822, 24345683, 10325460}, + YMinusX: FieldElement{-19855277, -1568885, -22202708, + 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007}, + XY2D: FieldElement{-21751364, -16730916, 1351763, + -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}}, + NielsPoint{YPlusX: FieldElement{15564307, + -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, + -8295852, 13296005}, YMinusX: FieldElement{-9442290, + 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, + -30000824, 12074674}, XY2D: FieldElement{4771191, + -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, + 29832613, -16391035}}, + NielsPoint{YPlusX: FieldElement{7064884, + -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, + 5293297, -27122660, 13101590}, YMinusX: FieldElement{-2298563, + 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, + -30356070, -4190957}, XY2D: FieldElement{-30006540, + 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, + 9515896, 19568978, 9628812}}, + NielsPoint{YPlusX: FieldElement{33053803, 199357, + 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, + 3437740}, YMinusX: FieldElement{-18978877, 3884493, + 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, + 4176122}, XY2D: FieldElement{-27124001, 10659917, + 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, + 24216882, 5944158}}, + NielsPoint{YPlusX: FieldElement{8894125, + 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, + 11632993, 5847885}, YMinusX: FieldElement{26942781, + -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, + -9727230, 4782140}, XY2D: FieldElement{19916461, -4828410, + -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, + -1873857}}, + NielsPoint{YPlusX: FieldElement{801428, + -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, + -13538503, 1387155}, YMinusX: FieldElement{19646058, + 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, + -21866831, 11835260}, XY2D: FieldElement{19299512, + 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, + -26560550, 5052483}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-3017432, + 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, + 12228557, -7003677}, YMinusX: FieldElement{32944382, + 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, + -6114803, 8653815}, XY2D: FieldElement{22865569, -4652735, + 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, + 2841751}}, + NielsPoint{YPlusX: FieldElement{-16420968, + -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, + 19932058, -12739203}, YMinusX: FieldElement{-11656086, + 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, + -4777469, -13910208}, XY2D: FieldElement{1382174, + -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, + -14013818, 3093230}}, + NielsPoint{YPlusX: FieldElement{16650921, + -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, + -24049421, -6691850}, YMinusX: FieldElement{-21911077, + -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, + 15193618, -21652117, -16739389}, XY2D: FieldElement{-9935934, + -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, + 17361620, 11864968}}, + NielsPoint{YPlusX: FieldElement{-11307610, + 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, + -25578460, -16240689}, YMinusX: FieldElement{14668462, + -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, + 9145645, -6443880}, XY2D: FieldElement{5974874, 3053895, + -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, + -3050304}}, + NielsPoint{YPlusX: FieldElement{30625386, + -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, + -16303496, -27999779, 1803632}, YMinusX: FieldElement{-3553091, + 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, + -21405489, 7047412}, XY2D: FieldElement{20093277, + 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, + -32343828, -10257566}}, + NielsPoint{YPlusX: FieldElement{-20788824, + 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, + -21679658, 2288038}, YMinusX: FieldElement{-26819236, + -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, + -24819617, 12570232}, XY2D: FieldElement{-1063558, + -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, + -11974704, 4724943}}, + NielsPoint{YPlusX: FieldElement{17960970, + -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, + -8659932, -29576300, 1903856}, YMinusX: FieldElement{23134274, + -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, + 3190296, 26955097, 14109738}, XY2D: FieldElement{15308788, + 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, + 31960942, 11934971}}, + NielsPoint{YPlusX: FieldElement{-27395711, + 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, + 10491392, 1379718}, YMinusX: FieldElement{-13159415, + 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, + 21432314, 12180697}, XY2D: FieldElement{-11787308, + 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, + -10301319, -13872883}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{5414091, + -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, + 26128231, 6032912}, YMinusX: FieldElement{-26337395, + -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, + 8316894, -25875034, -10437358}, XY2D: FieldElement{3296484, + 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, + 12376617, 3188849}}, + NielsPoint{YPlusX: FieldElement{29190488, + -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, + -16109234, -9852307}, YMinusX: FieldElement{-14744486, + -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, + 18640741, -960977}, XY2D: FieldElement{-6928835, + -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, + 10530747, 1053335}}, + NielsPoint{YPlusX: FieldElement{-29265967, + -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, + -2948985, 24018831, 15026644}, YMinusX: FieldElement{-22592535, + -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, + -2314791, -15145616}, XY2D: FieldElement{-27419985, + -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, + -23166419, -2531735}}, + NielsPoint{YPlusX: FieldElement{-21744398, + -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, + -5070217, 726099}, YMinusX: FieldElement{29370922, + -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, + 30007388, -15823341}, XY2D: FieldElement{-936379, + 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, + 9835848, 4555336}}, + NielsPoint{YPlusX: FieldElement{-23376435, + 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, + -11985298, 12422646}, YMinusX: FieldElement{31117226, + -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, + -4096706, 29120153, 13924425}, XY2D: FieldElement{-17400879, + -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, + -11317700, 7240931, -237388}}, + NielsPoint{YPlusX: FieldElement{-31361739, + -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, + 4389483, 3293637, -15551743}, YMinusX: FieldElement{-16684801, + -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, + 7733547, 12796905, -6335822}, XY2D: FieldElement{-8759414, + -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, + 3647836, 3222231, -11160462}}, + NielsPoint{YPlusX: FieldElement{18606113, 1693100, + -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, + 2484985}, YMinusX: FieldElement{9255317, -3131197, + -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, + -19802075, -3034702}, XY2D: FieldElement{-22729289, + 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, + -30097688, -10618797}}, + NielsPoint{YPlusX: FieldElement{21878590, + -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, + -7360503, -4109293}, YMinusX: FieldElement{27736861, + 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, + -23659143, -8132100}, XY2D: FieldElement{19492550, + -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, + 13243957, 8709688}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{12015105, + 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, + 5150968, 7274186}, YMinusX: FieldElement{2831366, + -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, + 31021603, -9793610}, XY2D: FieldElement{-2529932, + -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, + 15067285, -14147707}}, + NielsPoint{YPlusX: FieldElement{7840942, + 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, + -19379462, -12403220}, YMinusX: FieldElement{915865, + -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, + 8410997, -7220461, 16527025}, XY2D: FieldElement{32922597, + -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, + 23834301, 6588044}}, + NielsPoint{YPlusX: FieldElement{32752030, + 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, + -20314580, -1305992}, YMinusX: FieldElement{-4689649, + 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, + 1976123, -7249027}, XY2D: FieldElement{21251222, 16309901, + -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, + -8237197}}, + NielsPoint{YPlusX: FieldElement{8651614, + -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, + 10008136, -4667901}, YMinusX: FieldElement{31486080, + 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, + -13662089, 8684155, -10532952}, XY2D: FieldElement{19443825, + 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, + 31316348, 14219878}}, + NielsPoint{YPlusX: FieldElement{-28594490, + 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, + 29126555, 9207390}, YMinusX: FieldElement{32382935, + 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, + -7957600, -14435730}, XY2D: FieldElement{2814918, + 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, + 8550130, 28346258, 1994730}}, + NielsPoint{YPlusX: FieldElement{-19578299, + 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, + 22628102, 8115180}, YMinusX: FieldElement{-30405132, + 955511, -11133838, -15078069, -32447087, -13278079, -25651578, + 3317160, -9943017, 930272}, XY2D: FieldElement{-15303681, + -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, + -22765376, -10650715}}, + NielsPoint{YPlusX: FieldElement{-22751231, + -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, + -16554220, -1867018, 8398970}, YMinusX: FieldElement{-31969310, + 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, + 18009408, -15772772}, XY2D: FieldElement{-17220923, + -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, + 19288549, 1325865}}, + NielsPoint{YPlusX: FieldElement{15100157, + -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, + -3479146, 33166107, -8042750}, YMinusX: FieldElement{20909231, + 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, + 2213263, -13878373}, XY2D: FieldElement{32529814, + -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, + -5766928, 8371348}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{9923462, + 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, + -26442943, 10486144}, YMinusX: FieldElement{-22597207, + -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, + -23921530, -11455195}, XY2D: FieldElement{5408411, + -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, + 19985175, -3436086}}, + NielsPoint{YPlusX: FieldElement{-13994457, + 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, + 65030, 8370684}, YMinusX: FieldElement{-8320926, + -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, + 6922164, 12743482, -9800518}, XY2D: FieldElement{-2361371, + 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, + 18800704, 255233}}, + NielsPoint{YPlusX: FieldElement{-5269658, + -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, + 19258688, -14753793}, YMinusX: FieldElement{-2936654, + -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, + 2209390, -1524053, 2055794}, XY2D: FieldElement{580882, + 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, + -30021019, 7394435}}, + NielsPoint{YPlusX: FieldElement{23838809, 1822728, + -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, + 14799921}, YMinusX: FieldElement{13345610, 9759151, + 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, + 7402518}, XY2D: FieldElement{2286874, -4435931, -20042458, + -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}}, + NielsPoint{YPlusX: FieldElement{14414086, + -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, + 30019587, -9029278}, YMinusX: FieldElement{-27688051, + 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, + 9944378, 8024}, XY2D: FieldElement{4368715, -3709630, + 29874200, -15022983, -20230386, -11410704, -16114594, -999085, + -8142388, 5640030}}, + NielsPoint{YPlusX: FieldElement{10299610, + 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, + 15219798, -14327783}, YMinusX: FieldElement{27425505, + -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, + -18342183, 9742717}, XY2D: FieldElement{6744077, 2427284, + 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, + 1994844}}, + NielsPoint{YPlusX: FieldElement{14012521, + -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, + -10909803, 24319929, -6446333}, YMinusX: FieldElement{16412690, + -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, + -10484049, -30102368, -4739048}, XY2D: FieldElement{22397382, + -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, + 6199366, 21880021, -12250760}}, + NielsPoint{YPlusX: FieldElement{-4283307, 5368523, + -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, + 4957760}, YMinusX: FieldElement{-15447727, 709327, + -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, + -14796503, 5005757}, XY2D: FieldElement{-2114751, + -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, + -13239326, -16395286, -2176112}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-19025756, + 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, + 22208662, 2000468}, YMinusX: FieldElement{3065073, + -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, + -3691214, -7414184}, XY2D: FieldElement{10379208, + -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, + -3132688, 16400289}}, + NielsPoint{YPlusX: FieldElement{15716668, 1254266, + -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, + 9132066}, YMinusX: FieldElement{24158887, 12938817, + 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, + -2692882}, XY2D: FieldElement{13488534, 7794716, 22236231, + 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}}, + NielsPoint{YPlusX: FieldElement{16335052, + 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, + 15445875, -7798101}, YMinusX: FieldElement{29004207, + -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, + -278050, -15759279}, XY2D: FieldElement{-6122061, + -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, + -6976290, -29828287, -10815811}}, + NielsPoint{YPlusX: FieldElement{27081650, 3463984, + 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, + 960709}, YMinusX: FieldElement{20263915, 11434237, + -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, + -19384511, 7639714}, XY2D: FieldElement{-2830798, + -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, + -16043750, 29994677, -15808121}}, + NielsPoint{YPlusX: FieldElement{9769828, + 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, + -13860782, -31184575, 709464}, YMinusX: FieldElement{12286395, + 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, + -8890874, 16102007, 13205847}, XY2D: FieldElement{13733362, + 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, + 10151379, 10394400}}, + NielsPoint{YPlusX: FieldElement{4024660, + -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, + -33302334, 8934414}, YMinusX: FieldElement{-15879800, + -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, + -11536886, 11721158}, XY2D: FieldElement{17555939, + -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, + -9205489, -1280045}}, + NielsPoint{YPlusX: FieldElement{-461409, + -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, + 6108462, -6183415}, YMinusX: FieldElement{-5070281, + 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, + -26898490, -7867459}, XY2D: FieldElement{-31975283, + 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, + 7592688, -14992079}}, + NielsPoint{YPlusX: FieldElement{21594432, + -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, + -28256052, 4298412}, YMinusX: FieldElement{-20650503, + -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, + 13717174, 10805743}, XY2D: FieldElement{-14676630, + -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, + -26938930, -5863836}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{12962541, + 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, + -4381056, 9882022}, YMinusX: FieldElement{18512079, + 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, + -23967430, -3299429}, XY2D: FieldElement{-6789020, + -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, + -6661110, -2403099, 5276065}}, + NielsPoint{YPlusX: FieldElement{30169808, + -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, + 1449224, 13082861}, YMinusX: FieldElement{10342826, + 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, + -21016438, -8202000}, XY2D: FieldElement{-33150110, + 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, + -10300080, -11060101}}, + NielsPoint{YPlusX: FieldElement{32869458, + -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, + 2521008, -22664288, 6904815}, YMinusX: FieldElement{29506923, + 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, + -29003639, -6657642}, XY2D: FieldElement{10340844, + -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, + -11824370, -25584551, 5181966}}, + NielsPoint{YPlusX: FieldElement{25940115, + -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, + -16450922, -2322852, -12388574}, + YMinusX: FieldElement{-21765684, 9916823, -1300409, + 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742}, + XY2D: FieldElement{-18882287, -11673380, 24849422, + 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}}, + NielsPoint{YPlusX: FieldElement{12241050, + -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, + 16136752, 15264020}, YMinusX: FieldElement{-10349955, + -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, + 6671822, 19012087, 3772772}, XY2D: FieldElement{3753511, + -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, + 20527771, 12988982}}, + NielsPoint{YPlusX: FieldElement{-14822485, + -5797269, -3707987, 12689773, -898983, -10914866, -24183046, + -10564943, 3299665, -12424953}, + YMinusX: FieldElement{-16777703, -15253301, -9642417, + 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218}, + XY2D: FieldElement{-17226263, 1816362, -1673288, -6086439, + 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}}, + NielsPoint{YPlusX: FieldElement{29692663, 6829891, + -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, + -10647073}, YMinusX: FieldElement{-3481570, 8707081, + 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, + -2085325}, XY2D: FieldElement{-11587470, 14855945, + -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, + -14276837, -8400798}}, + NielsPoint{YPlusX: FieldElement{-4811456, + 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, + 13240845, 10965870}, YMinusX: FieldElement{-7742563, + -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, + 14147411, 29514390, 4302863}, XY2D: FieldElement{-13413405, + -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, + 17846988, -13971927}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-2244452, + -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, + -5222701, 12650267}, YMinusX: FieldElement{-9906797, + -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, + -19134326, 10958663}, XY2D: FieldElement{22470984, + 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, + -11574455, -25083830, 4271862}}, + NielsPoint{YPlusX: FieldElement{-25169565, + -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, + -32526221, 8469673}, YMinusX: FieldElement{15854970, + 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, + 24154791, -9460943}, XY2D: FieldElement{15446137, + -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, + 12840104, 24913809, 9815020}}, + NielsPoint{YPlusX: FieldElement{-4709286, + -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, + 13438769, 18735128, 9466238}, YMinusX: FieldElement{11933045, + 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, + -22728655, 16199064}, XY2D: FieldElement{14576810, + 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, + 30801119, 2164795}}, + NielsPoint{YPlusX: FieldElement{15995086, 3199873, + 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, + -13492807, 1268052}, YMinusX: FieldElement{-10290614, + -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, + -17055369, 3565904}, XY2D: FieldElement{29210088, + -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, + -10820713, -27162222, -14030531}}, + NielsPoint{YPlusX: FieldElement{-13161890, + 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, + 2244111, -14001979}, YMinusX: FieldElement{-5152875, + -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, + -16180800, 13491506, 4641841}, XY2D: FieldElement{10813417, + 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, + 14476989, -12767431}}, + NielsPoint{YPlusX: FieldElement{10292079, 9984945, + 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, + 12651324}, YMinusX: FieldElement{-31185513, -813383, + 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, + -3148940}, XY2D: FieldElement{10202177, -6545839, + -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, + 13216206, 14842320}}, + NielsPoint{YPlusX: FieldElement{-15815640, + -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, + 13765824, -27434397, 9900184}, YMinusX: FieldElement{14465505, + -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, + 15796406, -7051866, -8040114}, XY2D: FieldElement{30924417, + -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, + 9524356, -7018878}}, + NielsPoint{YPlusX: FieldElement{12274201, + -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, + 15663516, 4035784}, YMinusX: FieldElement{-2951309, + 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, + -22258478, 4659091}, XY2D: FieldElement{-16916263, + -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, + -2178256, -13455585}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-8858980, + -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, + 23440562, -290208}, YMinusX: FieldElement{10226241, + -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, + -16571960, -7442864}, XY2D: FieldElement{17932739, + -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, + -3646624, 3898661}}, + NielsPoint{YPlusX: FieldElement{7749907, + -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, + 21831162, 1245233}, YMinusX: FieldElement{26958459, + -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, + -30402091, -16716212}, XY2D: FieldElement{-12165896, + 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, + -22338025, 13987525}}, + NielsPoint{YPlusX: FieldElement{-24349909, + 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, + -7469781, -2858068}, YMinusX: FieldElement{9681908, + -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, + -14581012, 4091397}, XY2D: FieldElement{-8426427, + 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, + 29077877, -14741988}}, + NielsPoint{YPlusX: FieldElement{5269168, + -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, + -20017847, 2357889}, YMinusX: FieldElement{32264008, + -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, + -12869908, 5727338, 189038}, XY2D: FieldElement{14609123, + -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, + 10942115, -25888931, -14884697}}, + NielsPoint{YPlusX: FieldElement{20513500, 5557931, + -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, + -5137875}, YMinusX: FieldElement{-25574376, 11967826, + 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, + 8511905}, XY2D: FieldElement{-25656801, 3393631, -2955415, + -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}}, + NielsPoint{YPlusX: FieldElement{11630004, + 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, + -14395196, 8070818}, YMinusX: FieldElement{27117696, + -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, + 10483306, -11552749, -1028714}, XY2D: FieldElement{10637467, + -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, + -27493162, 15431203}}, + NielsPoint{YPlusX: FieldElement{20525145, + 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, + 14943142, -15056790, -7935931}, + YMinusX: FieldElement{-30024462, 5626926, -551567, + -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024}, + XY2D: FieldElement{-23752644, 2636870, -5163910, + -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}}, + NielsPoint{YPlusX: FieldElement{-1931799, + -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, + -13215537, -319204}, YMinusX: FieldElement{20239939, + 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, + -22750759, 14523817}, XY2D: FieldElement{27406042, + -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, + -30172742, -4805667}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{11374242, + 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, + -27727044, 11358504}, YMinusX: FieldElement{-12730809, + 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, + -26123651, 4985768}, XY2D: FieldElement{-19096303, + 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, + -19414307, -15621255}}, + NielsPoint{YPlusX: FieldElement{6490081, + 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, + -1691065, -9004790}, YMinusX: FieldElement{1656497, + 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, + -16796596, -5031438}, XY2D: FieldElement{-22273315, + -13524424, -64685, -4334223, -18605636, -10921968, -20571065, + -7007978, -99853, -10237333}}, + NielsPoint{YPlusX: FieldElement{17747465, + 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, + -15857976, -29260363, -5511971}, + YMinusX: FieldElement{31932027, -4986141, -19612382, + 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905}, + XY2D: FieldElement{29796507, 37186, 19818052, 10115756, + -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}}, + NielsPoint{YPlusX: FieldElement{12501286, 4044383, + -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, + -3659409}, YMinusX: FieldElement{6384877, 2899513, + 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, + 12071499}, XY2D: FieldElement{-8365515, -4042521, + 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, + 3829363}}, + NielsPoint{YPlusX: FieldElement{28425966, + -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, + 26333140, 14267664}, YMinusX: FieldElement{-11067219, + 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, + -8709488, -21761224, 8930324}, XY2D: FieldElement{-21197785, + -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, + -26491501, -16408940}}, + NielsPoint{YPlusX: FieldElement{13537262, + -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, + 6217254, -15943699, 13814990}, YMinusX: FieldElement{-17422573, + 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, + -1956526, -1776914}, XY2D: FieldElement{-25045300, + -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, + 12361135, -18685978, 4578290}}, + NielsPoint{YPlusX: FieldElement{24579768, 3711570, + 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, + 21964432, 8235257}, YMinusX: FieldElement{-6528613, + -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, + 13006806, 2355433}, XY2D: FieldElement{-16304899, + -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, + 1719366, 1141648, -12796236}}, + NielsPoint{YPlusX: FieldElement{-12863944, + -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, + -3133972, 32674895, 13715045}, YMinusX: FieldElement{11423335, + -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, + -28740881, -15642093}, XY2D: FieldElement{-1409668, + 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, + 7791794, -27245943, 4383347}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-28970898, + 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, + 27193557, 6245191}, YMinusX: FieldElement{-15193956, + 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, + 22510453, 8577507}, XY2D: FieldElement{-12632451, + 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, + -29571492, -3635906}}, + NielsPoint{YPlusX: FieldElement{3877321, + -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, + 5611860, 8164018}, YMinusX: FieldElement{-16275802, + 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, + 5773085, -8422109}, XY2D: FieldElement{-23788118, + -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, + 31632953, 190926}}, + NielsPoint{YPlusX: FieldElement{-24593607, + -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, + -25341555, -3627528}, YMinusX: FieldElement{8884438, + -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, + -1672488, 827625}, XY2D: FieldElement{-32720583, + -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, + -24878478, 1541286}}, + NielsPoint{YPlusX: FieldElement{2901347, + -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, + -3567481, 20456845, -1885033}, YMinusX: FieldElement{27019610, + 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, + -5016058, 29439641, 15138866}, XY2D: FieldElement{21536104, + -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, + -16361163, 7779328, 109896}}, + NielsPoint{YPlusX: FieldElement{30279744, + 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, + 23177719, -554075}, YMinusX: FieldElement{26572847, + 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, + 4439158, -13279347}, XY2D: FieldElement{-22716706, + 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, + -17717757, -5461437}}, + NielsPoint{YPlusX: FieldElement{-5056483, + 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, + 8550082, -15114165}, YMinusX: FieldElement{-18473302, + 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, + -23260460, -8428588}, XY2D: FieldElement{-32480551, + 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, + -21902570, 1494193}}, + NielsPoint{YPlusX: FieldElement{-19562091, + -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, + 8742704, 12967017}, YMinusX: FieldElement{-28464899, + 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, + -29903758, 15553883}, XY2D: FieldElement{21877909, + 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, + 19375923, -12647961}}, + NielsPoint{YPlusX: FieldElement{8832269, + -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, + 2862653, 9455043}, YMinusX: FieldElement{29306751, + 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, + 15511449, 4789663}, XY2D: FieldElement{-20679756, + 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, + 23513200, 16652362}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-33256173, + 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, + -18319198, 10212860}, YMinusX: FieldElement{2756081, + 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, + -9988298, -12506466}, XY2D: FieldElement{-24645692, + 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, + 864440, -2499677, -16710063}}, + NielsPoint{YPlusX: FieldElement{-26432803, + 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, + 2719757, 4940997}, YMinusX: FieldElement{-1323882, + 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, + 26699843, 5276295}, XY2D: FieldElement{-13149873, + -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, + -15452774, 7159369}}, + NielsPoint{YPlusX: FieldElement{9987780, + -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, + 22477218, -8403385}, YMinusX: FieldElement{18155857, + -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, + -22548173, 9334109}, XY2D: FieldElement{2986088, -4911893, + 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, + -22587149, 536906}}, + NielsPoint{YPlusX: FieldElement{4377756, + 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, + 10838060, -15420424}, YMinusX: FieldElement{-19342404, + 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, + 6378260, 699185}, XY2D: FieldElement{7895026, 4057113, + -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, + -13373962}}, + NielsPoint{YPlusX: FieldElement{-7737563, + -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, + -10962840, -3918636, -9669325}, YMinusX: FieldElement{10188286, + -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, + -21786507, 5427593}, XY2D: FieldElement{696102, 13206899, + 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, + 12477404}}, + NielsPoint{YPlusX: FieldElement{-11229439, + 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, + -23169516, 7733644}, YMinusX: FieldElement{17800790, + -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, + -10538171, 10322027, 15313801}, XY2D: FieldElement{26246234, + 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, + -24449242, 10890804}}, + NielsPoint{YPlusX: FieldElement{-31365647, + 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, + 16484931, 25180797, -5334884}, YMinusX: FieldElement{-586574, + 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, + 316878, 13820577}, XY2D: FieldElement{-9882808, -4510367, + -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, + -3712849}}, + NielsPoint{YPlusX: FieldElement{32988917, + -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, + -32349517, 7392473}, YMinusX: FieldElement{-8855661, + 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, + 25112947, -2926644}, XY2D: FieldElement{-2504044, + -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, + 5537438, -13914319}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-11225584, + 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, + 31234590, 6090599}, YMinusX: FieldElement{-9633316, + 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, + -6970405, -9034768}, XY2D: FieldElement{-27757857, + 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, + 20650474, 1804084}}, + NielsPoint{YPlusX: FieldElement{-27589786, + 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, + 27842616, -202328}, YMinusX: FieldElement{-15306973, + 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, + -11375082, 12714369}, XY2D: FieldElement{20807691, + -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, + 1035546, -19733229, 12796920}}, + NielsPoint{YPlusX: FieldElement{12076899, + -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, + -12899438, 3480665, -15182815}, + YMinusX: FieldElement{-32361549, 5457597, 28548107, + 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, + 2771025}, XY2D: FieldElement{-21389266, 421932, 26597266, + 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, + 15673397}}, + NielsPoint{YPlusX: FieldElement{-20184622, + 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, + 3727144, -12934448}, YMinusX: FieldElement{6120119, + 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, + 31123697, -10958981}, XY2D: FieldElement{30069250, + -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, + -16432438, 9648165}}, + NielsPoint{YPlusX: FieldElement{32705432, + -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, + -26008332, -11377501}, YMinusX: FieldElement{17219865, + 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, + 2662509, -16297073}, XY2D: FieldElement{-1172927, + -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, + 32247248, -14389861}}, + NielsPoint{YPlusX: FieldElement{14312628, 1221556, + 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, + -16027623, -13378845}, YMinusX: FieldElement{-1428825, + -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, + 17597934, 2346211}, XY2D: FieldElement{18510800, 15337574, + 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, + -11782870}}, + NielsPoint{YPlusX: FieldElement{10141598, 6082907, + 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, + 3592096}, YMinusX: FieldElement{33114168, -15889352, + -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, + -6837803}, XY2D: FieldElement{-32939165, -4255815, + 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, + 693168}}, + NielsPoint{YPlusX: FieldElement{30374239, 1595580, + -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, + 14369965}, YMinusX: FieldElement{-14370654, -7772529, + 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, + 16011505}, XY2D: FieldElement{18171223, -11934626, + -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, + 8764035, 12309598}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{5975908, + -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, + 1228319, 17544096, -10593782}, YMinusX: FieldElement{5811932, + -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, + -15410127, -5565381, 12348900}, XY2D: FieldElement{-31399660, + 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, + -10632534, -585479}}, + NielsPoint{YPlusX: FieldElement{-12675304, 694026, + -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, + 30944593, 1130208}, YMinusX: FieldElement{8247766, + -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, + 2488540, 23550156, -271232}, XY2D: FieldElement{17294316, + -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, + -408818, -137719}}, + NielsPoint{YPlusX: FieldElement{16091085, + -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, + 3260525, -7166271}, YMinusX: FieldElement{-4910104, + -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, + -13204905, -12748722, 2701326}, XY2D: FieldElement{-8574695, + 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, + 9276971, 11329923, 1862132}}, + NielsPoint{YPlusX: FieldElement{14763076, + -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, + -9037963, -940300}, YMinusX: FieldElement{8894987, + -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, + -15438168, 11595570}, XY2D: FieldElement{15214962, + 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, + -13489462, -4363670}}, + NielsPoint{YPlusX: FieldElement{-2538306, 7682793, + 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, + 699994}, YMinusX: FieldElement{-12466472, 4195084, + -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, + -14337913}, XY2D: FieldElement{31788461, -14507657, + 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, + -5409317}}, + NielsPoint{YPlusX: FieldElement{-25680606, + 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, + 29375955, 6024730}, YMinusX: FieldElement{842132, + -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, + -9940361, 2854096}, XY2D: FieldElement{-4847262, -7969331, + 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, + 16648078}}, + NielsPoint{YPlusX: FieldElement{-15218652, + 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, + 20237806, 2838411}, YMinusX: FieldElement{-19288047, + 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, + -13470457, 1068881, -12499905}, XY2D: FieldElement{-9558883, + -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, + 12521378, 4845654}}, + NielsPoint{YPlusX: FieldElement{-28198521, + 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, + -6482306, -12885870}, YMinusX: FieldElement{-23561822, + 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, + -1240216, -3113227, 13974498}, XY2D: FieldElement{12966261, + 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, + 18895762, 12629579}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{14741879, + -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, + 32195181, 3895677}, YMinusX: FieldElement{10758205, + 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, + -8982069, 4429647}, XY2D: FieldElement{-2453894, 15725973, + -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, + 18047436, -15281743}}, + NielsPoint{YPlusX: FieldElement{-25173001, + -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, + -12850837, -17620701, -9408468}, + YMinusX: FieldElement{21987233, 700364, -24505048, + 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375}, + XY2D: FieldElement{-25568350, 454463, -13211935, 16126715, + 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}}, + NielsPoint{YPlusX: FieldElement{6028182, + 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, + -1721788, -2776725}, YMinusX: FieldElement{-12278994, + 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, + 28408820, 6816612}, XY2D: FieldElement{-10358094, + -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, + -10339570, 5067943}}, + NielsPoint{YPlusX: FieldElement{-30505967, + -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, + 5331210, -10105944}, YMinusX: FieldElement{30528811, + 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, + 27679908, -1648928}, XY2D: FieldElement{9402404, + -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, + -8685565, 22611444, -12715406}}, + NielsPoint{YPlusX: FieldElement{22190590, 1118029, + 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, + 6622139}, YMinusX: FieldElement{-8310738, -2953450, + -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, + 13001963}, XY2D: FieldElement{-31241838, -15415700, + -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, + -15405155, 11020693}}, + NielsPoint{YPlusX: FieldElement{1866042, + -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, + 28761762, 1406734}, YMinusX: FieldElement{-448555, + -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, + 25577411, -13378680}, XY2D: FieldElement{-24290378, + 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, + -9368926, 4745410}}, + NielsPoint{YPlusX: FieldElement{-9141284, 6049714, + -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, + 10931924, -11931931}, YMinusX: FieldElement{-16561513, + 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, + -20470770, 13434654}, XY2D: FieldElement{22759489, + -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, + -12654326, 28445307, -5364710}}, + NielsPoint{YPlusX: FieldElement{29875063, + 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, + 9074234, 1167180}, YMinusX: FieldElement{-26205683, + 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, + 3843903, 9367684}, XY2D: FieldElement{-10969595, -6403711, + 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, + 4242895}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{22092954, + -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, + 2470660, -27417366, 16625501}, YMinusX: FieldElement{-11057722, + 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, + -27351616, 14247413}, XY2D: FieldElement{6314175, + -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, + 27108877, -1180880}}, + NielsPoint{YPlusX: FieldElement{-8586597, + -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, + -11058889, -27148451, 981874}, YMinusX: FieldElement{22833440, + 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, + -13970780, -10479804, -16197962}, XY2D: FieldElement{-7768587, + 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, + -15933690, 3797899}}, + NielsPoint{YPlusX: FieldElement{21721356, + -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, + 20491983, -8042152}, YMinusX: FieldElement{9209270, + -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, + 30997318, -6703063}, XY2D: FieldElement{7392032, 16618386, + 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, + 17649998, -250080}}, + NielsPoint{YPlusX: FieldElement{-9301088, + -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, + -9525724, -2233253, 7662146}, YMinusX: FieldElement{-17558673, + 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, + -3174674, 3440183}, XY2D: FieldElement{-19889700, + -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, + 4862400, 1133}}, + NielsPoint{YPlusX: FieldElement{-32856209, + -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, + -30594991, -7379421}, YMinusX: FieldElement{-3773428, + -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, + 18278453, 15405622}, XY2D: FieldElement{-4381906, + 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, + -21875062, 13626197}}, + NielsPoint{YPlusX: FieldElement{2281448, + -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, + 3953792, 13340839, 15928663}, YMinusX: FieldElement{31727126, + -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, + -7014826, -23452306, 5964753}, XY2D: FieldElement{4100420, + -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, + 11344144, 2538215, -7570755}}, + NielsPoint{YPlusX: FieldElement{-9433605, 6123113, + 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, + -15958862}, YMinusX: FieldElement{-26804558, 4260919, + 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, + 11659922, -11115118}, XY2D: FieldElement{26180396, + 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, + 33100372, -1306171}}, + NielsPoint{YPlusX: FieldElement{15121113, + -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, + 4486675, -5931810, -14466380}, YMinusX: FieldElement{16166486, + -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, + -10735770, -10039824}, XY2D: FieldElement{28042865, + -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, + 18036436, 5803270}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-817581, + 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, + -6159431, -14117438}, YMinusX: FieldElement{-31031306, + -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, + -20095739, 11763584}, XY2D: FieldElement{-594563, + -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, + -19773211, -10713562}}, + NielsPoint{YPlusX: FieldElement{30464590, + -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, + 2075773, -17020157, 992471}, YMinusX: FieldElement{18357185, + -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, + -11574335, -10601610}, XY2D: FieldElement{19598397, + 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, + 26224780, 16452269}}, + NielsPoint{YPlusX: FieldElement{-30223925, + 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, + -20533829, 3698650}, YMinusX: FieldElement{14187449, + 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, + -10890444, 27394301, 12015369}, XY2D: FieldElement{19695761, + 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, + -13259127, -3402461}}, + NielsPoint{YPlusX: FieldElement{30860103, + 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, + -8550524, -10393462}, YMinusX: FieldElement{-5719826, + -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, + -15118654, -4976164, 12651793}, XY2D: FieldElement{-2848395, + 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, + -16517902, 9768698, -2533218}}, + NielsPoint{YPlusX: FieldElement{-24719459, + 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, + 4940095, 10678226}, YMinusX: FieldElement{18860224, + 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, + 13944024, -24372348, 16582019}, XY2D: FieldElement{-15504260, + 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, + -11003761, 7989037}}, + NielsPoint{YPlusX: FieldElement{31490452, 5568061, + -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, + -14800171}, YMinusX: FieldElement{-17308668, -15879940, + -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, + -6857132}, XY2D: FieldElement{-28126887, -5688091, + 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, + 5988841}}, + NielsPoint{YPlusX: FieldElement{21890435, + -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, + -4470481, 24618407, 8283181}, YMinusX: FieldElement{-33136107, + -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, + 1466169, 10740210}, XY2D: FieldElement{-1509399, + -15488185, -13503385, -10655916, 32799044, 909394, -13938903, + -5779719, -32164649, -15327040}}, + NielsPoint{YPlusX: FieldElement{3960823, + -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, + 951507, -3260321, -573935}, YMinusX: FieldElement{24740841, + 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, + -7380369, -6144105}, XY2D: FieldElement{-28888365, + 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, + -14453128, -1625486, -6494814}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{793299, + -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, + -9906200, -621852}, YMinusX: FieldElement{5666233, + 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, + -6171428, -15186581}, XY2D: FieldElement{-4859255, + -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, + -1558923, -9863646}}, + NielsPoint{YPlusX: FieldElement{10896332, + -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, + -30581476, -15757844}, YMinusX: FieldElement{10566929, + 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, + 8822496, 24003793, 14264025}, XY2D: FieldElement{27713862, + -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, + 13958495, -5732453}}, + NielsPoint{YPlusX: FieldElement{-23481610, + 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, + 7340521, -15410068}, YMinusX: FieldElement{4646514, + -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, + -15066784, -10375192}, XY2D: FieldElement{-17270517, + 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, + -8843694, 3849921}}, + NielsPoint{YPlusX: FieldElement{-9064912, 2103172, + 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, + -15550259}, YMinusX: FieldElement{-12057553, -11177906, + 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, + -25845716, 12741426}, XY2D: FieldElement{-5946367, + 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, + 28834118, -7646072}}, + NielsPoint{YPlusX: FieldElement{-17335748, + -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, + 20461858, 5491305}, YMinusX: FieldElement{13669248, + -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, + 11293807, -28588204, -9421832}, XY2D: FieldElement{28497928, + 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, + 29867745, -8795943}}, + NielsPoint{YPlusX: FieldElement{-16207023, + 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, + -13175392, 22853429, -4012011}, YMinusX: FieldElement{24191378, + 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, + 12876623, -2112447}, XY2D: FieldElement{17902668, + 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, + 16031844, 3723494}}, + NielsPoint{YPlusX: FieldElement{-28632773, + 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, + 23896954, -4314245}, YMinusX: FieldElement{-20005381, + -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, + -9919646, -8826859}, XY2D: FieldElement{28816045, 298879, + -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, + -18051778, -2082915}}, + NielsPoint{YPlusX: FieldElement{16000882, -344896, + 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, + -19715240, 7847707}, YMinusX: FieldElement{10151868, + 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, + -10020567, 3852848}, XY2D: FieldElement{-11430470, + 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, + 29330899, -15076224}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-25499735, + -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, + -27548796, 12314391}, YMinusX: FieldElement{15683520, + -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, + 16103996, -3731215}, XY2D: FieldElement{-23169824, + -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, + 5402699, -29815713, -9841101}}, + NielsPoint{YPlusX: FieldElement{23190676, 2384583, + -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, + -25205859, 2739713}, YMinusX: FieldElement{21374101, + -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, + 4931255, 11987849}, XY2D: FieldElement{-7732, -2978858, + -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, + 10117930}}, + NielsPoint{YPlusX: FieldElement{-29501170, + -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, + 6704079, 12890019, 15728940}, YMinusX: FieldElement{-21972360, + -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, + 12885167, 8311031}, XY2D: FieldElement{-17516482, + 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, + 1888765, -5435404}}, + NielsPoint{YPlusX: FieldElement{-25817338, + -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, + -12707869, -19464434, -3340243}, + YMinusX: FieldElement{-23607977, -2665774, -526091, + 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116}, + XY2D: FieldElement{-24830458, -12733720, -15165978, + 10367250, -29530908, -265356, 22825805, -7087279, -16866484, + 16176525}}, + NielsPoint{YPlusX: FieldElement{-23583256, + 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, + -28746253, -10197509}, YMinusX: FieldElement{-10626600, + -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, + 32808310, 1099883}, XY2D: FieldElement{15030977, 5768825, + -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, + 2051441, -15225865}}, + NielsPoint{YPlusX: FieldElement{-3362323, + -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, + -22686354, 16633660}, YMinusX: FieldElement{4577086, + -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, + -10759549, 8402478, -9864273}, XY2D: FieldElement{-28406330, + -1051581, -26790155, -907698, -17212414, -11030789, 9453451, + -14980072, 17983010, 9967138}}, + NielsPoint{YPlusX: FieldElement{-25762494, + 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, + 17507396, 3651560}, YMinusX: FieldElement{-10420457, + -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, + -18553322, -11357135}, XY2D: FieldElement{2839101, + 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, + -5605463, -7621941}}, + NielsPoint{YPlusX: FieldElement{-4839289, + -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, + 17258084, -7977739}, YMinusX: FieldElement{18164541, + -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, + -15217008, 26908270, 12150756}, XY2D: FieldElement{-30264870, + -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, + -32302074, 16215819}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-6898905, + 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, + -7503072, -8675347}, YMinusX: FieldElement{-27343522, + -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, + 21676107, -1943028}, XY2D: FieldElement{21260961, + -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, + -6215466, -3556191, -7913075}}, + NielsPoint{YPlusX: FieldElement{16544754, + 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, + -18907032, -9662799}, YMinusX: FieldElement{-2415239, + -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, + 16690659, 25459437, -4564609}, XY2D: FieldElement{-25144690, + 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, + -6432418, -1644817}}, + NielsPoint{YPlusX: FieldElement{-23104652, + 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, + -16344658, 6335692, 7249989}, YMinusX: FieldElement{-30333227, + 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, + 2682242, 25993170, -12478523}, XY2D: FieldElement{4364628, + 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, + 31820368, 15075278}}, + NielsPoint{YPlusX: FieldElement{31879134, + -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, + -17970238, 12833045}, YMinusX: FieldElement{19073683, + 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, + 2074449, -9413939, 14905377}, XY2D: FieldElement{24483667, + -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, + 9253129, 27628530, -7555480}}, + NielsPoint{YPlusX: FieldElement{17597607, 8340603, + 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, + 15297016}, YMinusX: FieldElement{510886, 14337390, + -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, + 2921426}, XY2D: FieldElement{18606791, 11874196, 27155355, + -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}}, + NielsPoint{YPlusX: FieldElement{13609624, + 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, + 4389687, 288396}, YMinusX: FieldElement{9922506, -519394, + 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, + 16052080}, XY2D: FieldElement{12720016, 11937594, + -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, + -14754271, -10812892}}, + NielsPoint{YPlusX: FieldElement{15961858, + 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, + -28822128, 929275}, YMinusX: FieldElement{11038231, + -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, + -9371869, -21393143, 2465074}, XY2D: FieldElement{20017163, + -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, + 2463391, -4622140}}, + NielsPoint{YPlusX: FieldElement{-16358878, + -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, + 4003896, 12673717}, YMinusX: FieldElement{-1731589, + -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, + 7903886, 2348101}, XY2D: FieldElement{24536016, -16515207, + 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, + 10048127}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-12622226, + -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, + -32297756, 15221632}, YMinusX: FieldElement{-26478122, + -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, + 29769758, 6593415}, XY2D: FieldElement{-31994208, + -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, + 30958054, 8292160}}, + NielsPoint{YPlusX: FieldElement{31429822, + -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, + 26143136, -3148876}, YMinusX: FieldElement{22648901, + 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, + -3758243, -2304625}, XY2D: FieldElement{-15491917, + 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, + -1535569, -16664475, 8194478}}, + NielsPoint{YPlusX: FieldElement{27338066, + -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, + 28572286, 3005164}, YMinusX: FieldElement{26287124, + 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, + -26094821, -13079595}, XY2D: FieldElement{-7171154, + 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, + 32208683, -1198248}}, + NielsPoint{YPlusX: FieldElement{-16657702, + 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, + -27672585, -11539858}, YMinusX: FieldElement{15941029, + -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, + 15397331, -4130193}, XY2D: FieldElement{8934485, + -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, + -1441021, -27505566, 15087184}}, + NielsPoint{YPlusX: FieldElement{-18357243, + -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, + 11461896, 16788528, -5868942}, YMinusX: FieldElement{-1947386, + 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, + -10323320, 31322514, -11615635}, XY2D: FieldElement{21426655, + -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, + -14621414, 13040862, -12112948}}, + NielsPoint{YPlusX: FieldElement{11293895, + 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, + -13417103, 1613711, 4896935}, YMinusX: FieldElement{-25894883, + 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, + -23971776, -11267415}, XY2D: FieldElement{-15924766, + -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, + -23753030, -8436416}}, + NielsPoint{YPlusX: FieldElement{-7091295, + 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, + 23097949, -566018}, YMinusX: FieldElement{4565804, + -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, + -18512313, 2424778}, XY2D: FieldElement{366633, -11976806, + 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, + 12412659}}, + NielsPoint{YPlusX: FieldElement{-24001791, + 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, + -3141501, 11179385}, YMinusX: FieldElement{18289522, + -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, + -18684645, -11443503}, XY2D: FieldElement{476239, + 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, + 11052904, 5219329}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{20678546, + -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, + 9014762, -8579056}, YMinusX: FieldElement{-13644050, + -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, + 9160280, 8473550, -3256838}, XY2D: FieldElement{24900749, + 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, + -16335821, -24568481, 11788948}}, + NielsPoint{YPlusX: FieldElement{-3118155, + -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, + 10410733, -24568470, -1458691}, + YMinusX: FieldElement{-15659161, 16736706, -22467150, + 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118}, + XY2D: FieldElement{-23400612, 8348507, -14585951, + -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}}, + NielsPoint{YPlusX: FieldElement{-20186973, + -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, + -8940735, -5818269}, YMinusX: FieldElement{-6948785, + -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, + -12838188, 28358192, -4253904}, XY2D: FieldElement{-23561781, + -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, + 4072016, -5351664, 5596589}}, + NielsPoint{YPlusX: FieldElement{-28236598, + -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, + 1768301, 15373193}, YMinusX: FieldElement{-7243358, + -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, + -24660491, 3442910}, XY2D: FieldElement{-30210571, + 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, + -18585478, 13365930}}, + NielsPoint{YPlusX: FieldElement{-7877390, + -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, + -9689599, -3031667}, YMinusX: FieldElement{25008904, + -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, + 15723479, -15163481}, XY2D: FieldElement{-9660625, + 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, + 5400171, 519526, -1235876}}, + NielsPoint{YPlusX: FieldElement{22258397, + -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, + 7315967, 16648397, 7605640}, YMinusX: FieldElement{-8081308, + -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, + -9468848, 4763278}, XY2D: FieldElement{-21699244, + 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, + -11356529, 728112}}, + NielsPoint{YPlusX: FieldElement{26047220, + -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, + -12555558, -29365436, -5498272}, + YMinusX: FieldElement{17510331, -322857, 5854289, + 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012}, + XY2D: FieldElement{-10312768, 3936952, 9156313, -8897683, + 16498692, -994647, -27481051, -666732, 3424691, 7540221}}, + NielsPoint{YPlusX: FieldElement{30322361, + -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, + -9244265, 15258046}, YMinusX: FieldElement{13054562, + -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, + 1062915, -5136345}, XY2D: FieldElement{-19240248, + -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, + 12194497, 32960380, 1459310}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{19852034, + 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, + 18638003, -11174937}, YMinusX: FieldElement{31395534, + 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, + -6643087, -5442636}, XY2D: FieldElement{-9192165, + -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, + -32294889, -6456008}}, + NielsPoint{YPlusX: FieldElement{-2444496, -149937, + 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, + -8138429}, YMinusX: FieldElement{-15236356, -15433509, + 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, + 5203576}, XY2D: FieldElement{31834314, 14135496, -770007, + 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}}, + NielsPoint{YPlusX: FieldElement{-9606723, + -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, + -12211255, 15192876, -2087490}, + YMinusX: FieldElement{-12663563, -2181719, 1168162, + -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, + -13382104}, XY2D: FieldElement{33184999, 11180355, + 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, + 14480053}}, + NielsPoint{YPlusX: FieldElement{31308717, + -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, + 27595050, 8737275}, YMinusX: FieldElement{-20318852, + -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, + -12610604, 26498114, 66511}, XY2D: FieldElement{22644454, + -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, + -13327787, -7515095}}, + NielsPoint{YPlusX: FieldElement{-28017847, + 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, + -17127465, 15115439}, YMinusX: FieldElement{23711543, + -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, + 8236921, 16492939}, XY2D: FieldElement{-23910559, + -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, + 10071562, 6708380, -6222424}}, + NielsPoint{YPlusX: FieldElement{2101391, + -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, + 29955601, -11678310}, YMinusX: FieldElement{3096359, + 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, + -12635595, -9917575, 6216608}, XY2D: FieldElement{-32615849, + 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, + -26767480, 7525079}}, + NielsPoint{YPlusX: FieldElement{-23066649, + -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, + -19386633, 11994101}, YMinusX: FieldElement{21691500, + -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, + -7477437, 13381418}, XY2D: FieldElement{18445390, + -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, + 28535282, 15779576}}, + NielsPoint{YPlusX: FieldElement{30098053, 3089662, + -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, + 9955285, -16303356}, YMinusX: FieldElement{9734894, + -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, + 20194861, 13380996}, XY2D: FieldElement{-26378102, + -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, + 15707771, 26342023, 10146099}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{-26016874, + -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, + 21612326, -545728}, YMinusX: FieldElement{-13077387, + 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, + -20856566, 11649658}, XY2D: FieldElement{-10031494, + 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, + 33514190, 2333242}}, + NielsPoint{YPlusX: FieldElement{-21433588, + -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, + 24350578, -13450001}, YMinusX: FieldElement{-4116307, + -11271533, -23886186, 4843615, -30088339, 690623, -31536088, + -10406836, 8317860, 12352766}, XY2D: FieldElement{18200138, + -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, + -2287550, 20712163, 6719373}}, + NielsPoint{YPlusX: FieldElement{26656208, 6075253, + -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, + -3297458}, YMinusX: FieldElement{-17168938, -14854097, + -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, + -16428628}, XY2D: FieldElement{-13323321, 13325349, + 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, + -16479657}}, + NielsPoint{YPlusX: FieldElement{-23860538, + -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, + -5240639, 13735342, 1934062}, YMinusX: FieldElement{25089769, + 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, + -3765346, -21277997, 5473616}, XY2D: FieldElement{31883677, + -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, + 29111212, -5451014}}, + NielsPoint{YPlusX: FieldElement{24244947, + -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, + 6388839, -10295587, 452383}, YMinusX: FieldElement{-25640782, + -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, + 15766062, 8407814}, XY2D: FieldElement{-20406999, + 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, + -8067909, 2276718}}, + NielsPoint{YPlusX: FieldElement{30157918, + 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, + 22740376, -7303417}, YMinusX: FieldElement{2041139, + -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, + 13742383, -15637599, 13295222}, XY2D: FieldElement{33338237, + -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, + -4451357, -14669444}}, + NielsPoint{YPlusX: FieldElement{-20045281, + 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, + 7770569, 9620597}, YMinusX: FieldElement{23208068, + 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, + -33502340, -14767970}, XY2D: FieldElement{1439958, + -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, + 30494170, -11440799}}, + NielsPoint{YPlusX: FieldElement{-5037580, + -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, + -1684339, -13333647}, YMinusX: FieldElement{13908495, + -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, + 3353509, 4033511}, XY2D: FieldElement{-29663431, + -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, + 27485041, 7356032}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{9661027, + 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, + 28431036, -16771834}, YMinusX: FieldElement{-23839233, + -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, + 14150565, 15970762, 4099461}, XY2D: FieldElement{29262576, + 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, + 11465739, 8317062}}, + NielsPoint{YPlusX: FieldElement{-25493081, + -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, + 20969334, -5157516}, YMinusX: FieldElement{-20384450, + -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, + -3649888, 11177095, 14989547}, XY2D: FieldElement{-24496721, + -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, + -28487508, 9930240}}, + NielsPoint{YPlusX: FieldElement{-17751622, + -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, + -13403753, 16291481, -5314038}, + YMinusX: FieldElement{-33229194, 2553288, 32678213, + 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741}, + XY2D: FieldElement{16660756, 7281060, -10830758, 12911820, + 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}}, + NielsPoint{YPlusX: FieldElement{-19765507, + 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, + -30190403, 4782747}, YMinusX: FieldElement{-1354539, + 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, + 22546403, 437323}, XY2D: FieldElement{31665577, -12180464, + -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, + -14097016}}, + NielsPoint{YPlusX: FieldElement{-14467279, + -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, + -19284671, -6114373}, YMinusX: FieldElement{15121312, + -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, + 15496498, -29380133, 11754228}, XY2D: FieldElement{-2637277, + -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, + 22761615, -10134141}}, + NielsPoint{YPlusX: FieldElement{16918416, + 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, + -12227393, 32851222, 11717399}, YMinusX: FieldElement{11166634, + 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, + -1193175, -4030831}, XY2D: FieldElement{-185635, 9921305, + 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, + -19985279, -3948376}}, + NielsPoint{YPlusX: FieldElement{-32460596, + 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, + -30772034, -15486313}, YMinusX: FieldElement{-18006477, + 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, + -16049879, 10928917, 3011958}, XY2D: FieldElement{-6957757, + -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, + 18008031, 10258577}}, + NielsPoint{YPlusX: FieldElement{-22448644, + 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, + 25127874, 6671743}, YMinusX: FieldElement{29701166, + -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, + 25838796, 4642684}, XY2D: FieldElement{-20430234, + 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, + 18423289, 4177476}}}} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_radix51.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_radix51.go new file mode 100644 index 0000000000..f3a7b236e3 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/table_radix51.go @@ -0,0 +1,1540 @@ +// +build amd64,!forcegeneric go1.13,!forcegeneric + +package edwards25519 + +var BaseScalarMultTable = ScalarMultTable{[8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x636186c1936d, + 0x69d5f4b76bf78, 0x721035676afa2, 0x6a171bb9e6e3b, 0x25fe4b16714ab}, + YMinusX: FieldElement{0x55ba063a5c7c9, 0x7f335ac5bb3a7, + 0x706678471f6a2, 0x5dd945f9ee8d3, 0x536857d574db}, + XY2D: FieldElement{0x6edfa78855585, 0x3866aa76c2a86, + 0x2f299cf64985f, 0x52bd2f2411a11, 0x10ee849760f39}}, + NielsPoint{YPlusX: FieldElement{0x318036cc38e16, + 0x530be01494dbb, 0xa7e3f582e589, 0xe8d2acb2cd0f, 0x26f3f9c05782d}, + YMinusX: FieldElement{0x65a9fbd4b2a45, 0x67633ea612eac, + 0x2472155c351fb, 0x5550fb0ee4a27, 0x144a6a599636d}, + XY2D: FieldElement{0x2a8b3a59b7a5f, 0x3abb359ef087f, + 0x4f5a8c4db05af, 0x5b9a807d04205, 0x701af5b13ea50}}, + NielsPoint{YPlusX: FieldElement{0x50a5712028e02, + 0xdeb9be97bcab, 0x44ba42c21bbc9, 0x7ede4194890d, 0x4474c759a40e5}, + YMinusX: FieldElement{0x729f5a9768ab1, 0x502ef1baf77df, + 0x74d568cc67f42, 0x73924bc5eb386, 0x1b1680705cce5}, + XY2D: FieldElement{0x16cc0f22f2764, 0x3bc7944b3bd6a, + 0x43492ce9daf73, 0x59c97478d5d39, 0x25d7d950ed464}}, + NielsPoint{YPlusX: FieldElement{0x351b98efc099f, + 0x68fbfa4a7050e, 0x42a49959d971b, 0x393e51a469efd, 0x680e910321e58}, + YMinusX: FieldElement{0x6050a056818bf, 0x62acc1f5532bf, + 0x28141ccc9fa25, 0x24d61f471e683, 0x27933f4c7445a}, + XY2D: FieldElement{0x3fbe9c476ff09, 0xaf6b982e4b42, + 0xad1251ba78e5, 0x715aeedee7c88, 0x7f9d0cbf63553}}, + NielsPoint{YPlusX: FieldElement{0x70e187f49fcc4, + 0x666d4fd9d1109, 0x25968a3a052f6, 0x7eef04b8cfa43, 0x1aa2b7523c606}, + YMinusX: FieldElement{0x1b796b61f72a7, 0x1d2b434600f91, + 0x19c9a04c1c9df, 0x6ba47bb06c8a3, 0x4f963b5b983a9}, + XY2D: FieldElement{0x4240e7ed57d68, 0x705e845c06868, + 0x109634b63c7df, 0x4b2a5f24c7a72, 0x3c55419694c44}}, + NielsPoint{YPlusX: FieldElement{0x3111488ea8ebc, + 0x6dfe6ea0ef8be, 0x69963259363a9, 0x3a13fcd24cb92, 0x2e1a84495d33c}, + YMinusX: FieldElement{0x7f94984827349, 0x77b05bb18d6cc, + 0x6eab11aa29075, 0x3bda27bd18c6f, 0x4749b3be51be8}, + XY2D: FieldElement{0x4326702ea4b71, 0x6834376030b5, + 0xef0512f9c380, 0xf1a9f2512584, 0x10b8e91a9f0d6}}, + NielsPoint{YPlusX: FieldElement{0x6586ec215de3d, + 0x48046bf5815b3, 0x96a854814e31, 0x69492b449b53, 0x5d39762680550}, + YMinusX: FieldElement{0x755735c0627ef, 0x66439364a8514, + 0x69775b6c2e312, 0x71c361d24b791, 0xea812ce8e18}, + XY2D: FieldElement{0x49237fe474c4b, 0x71f582b6ca1cf, + 0x621483133f282, 0x7ac56b1df22d3, 0x56044e395f06}}, + NielsPoint{YPlusX: FieldElement{0x7596604dd3e8f, + 0x6fc510e058b36, 0x3670c8db2cc0d, 0x297d899ce332f, 0x915e76061bce}, + YMinusX: FieldElement{0x75dedf39234d9, 0x1c36ab1f3c54, + 0xf08fee58f5da, 0xe19613a0d637, 0x3a9024a1320e0}, + XY2D: FieldElement{0x1f5d9c9a2911a, 0x7117994fafcf8, + 0x2d8a8cae28dc5, 0x74ab1b2090c87, 0x26907c5c2ecc4}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x4dd0e632f9c1d, + 0x2ced12622a5d9, 0x18de9614742da, 0x79ca96fdbb5d4, 0x6dd37d49a00ee}, + YMinusX: FieldElement{0x3635449aa515e, 0x3e178d0475dab, + 0x50b4712a19712, 0x2dcc2860ff4ad, 0x30d76d6f03d31}, + XY2D: FieldElement{0x444172106e4c7, 0x1251afed2d88, + 0x534fc9bed4f5a, 0x5d85a39cf5234, 0x10c697112e864}}, + NielsPoint{YPlusX: FieldElement{0x62aa08358c805, + 0x46f440848e194, 0x447b771a8f52b, 0x377ba3269d31d, 0x3bf9baf55080}, + YMinusX: FieldElement{0x3c4277dbe5fde, 0x5a335afd44c92, + 0xc1164099753e, 0x70487006fe423, 0x25e61cabed66f}, + XY2D: FieldElement{0x3e128cc586604, 0x5968b2e8fc7e2, + 0x49a3d5bd61cf, 0x116505b1ef6e6, 0x566d78634586e}}, + NielsPoint{YPlusX: FieldElement{0x54285c65a2fd0, + 0x55e62ccf87420, 0x46bb961b19044, 0x1153405712039, 0x14fba5f34793b}, + YMinusX: FieldElement{0x7a49f9cc10834, 0x2b513788a22c6, + 0x5ff4b6ef2395b, 0x2ec8e5af607bf, 0x33975bca5ecc3}, + XY2D: FieldElement{0x746166985f7d4, 0x9939000ae79a, + 0x5844c7964f97a, 0x13617e1f95b3d, 0x14829cea83fc5}}, + NielsPoint{YPlusX: FieldElement{0x70b2f4e71ecb8, + 0x728148efc643c, 0x753e03995b76, 0x5bf5fb2ab6767, 0x5fc3bc4535d7}, + YMinusX: FieldElement{0x37b8497dd95c2, 0x61549d6b4ffe8, + 0x217a22db1d138, 0xb9cf062eb09e, 0x2fd9c71e5f758}, + XY2D: FieldElement{0xb3ae52afdedd, 0x19da76619e497, + 0x6fa0654d2558e, 0x78219d25e41d4, 0x373767475c651}}, + NielsPoint{YPlusX: FieldElement{0x95cb14246590, + 0x2d82aa6ac68, 0x442f183bc4851, 0x6464f1c0a0644, 0x6bf5905730907}, + YMinusX: FieldElement{0x299fd40d1add9, 0x5f2de9a04e5f7, + 0x7c0eebacc1c59, 0x4cca1b1f8290a, 0x1fbea56c3b18f}, + XY2D: FieldElement{0x778f1e1415b8a, 0x6f75874efc1f4, + 0x28a694019027f, 0x52b37a96bdc4d, 0x2521cf67a635}}, + NielsPoint{YPlusX: FieldElement{0x46720772f5ee4, + 0x632c0f359d622, 0x2b2092ba3e252, 0x662257c112680, 0x1753d9f7cd6}, + YMinusX: FieldElement{0x7ee0b0a9d5294, 0x381fbeb4cca27, + 0x7841f3a3e639d, 0x676ea30c3445f, 0x3fa00a7e71382}, + XY2D: FieldElement{0x1232d963ddb34, 0x35692e70b078d, + 0x247ca14777a1f, 0x6db556be8fcd0, 0x12b5fe2fa048e}}, + NielsPoint{YPlusX: FieldElement{0x37c26ad6f1e92, + 0x46a0971227be5, 0x4722f0d2d9b4c, 0x3dc46204ee03a, 0x6f7e93c20796c}, + YMinusX: FieldElement{0xfbc496fce34d, 0x575be6b7dae3e, + 0x4a31585cee609, 0x37e9023930ff, 0x749b76f96fb12}, + XY2D: FieldElement{0x2f604aea6ae05, 0x637dc939323eb, + 0x3fdad9b048d47, 0xa8b0d4045af7, 0xfcec10f01e02}}, + NielsPoint{YPlusX: FieldElement{0x2d29dc4244e45, + 0x6927b1bc147be, 0x308534ac0839, 0x4853664033f41, 0x413779166feab}, + YMinusX: FieldElement{0x558a649fe1e44, 0x44635aeefcc89, + 0x1ff434887f2ba, 0xf981220e2d44, 0x4901aa7183c51}, + XY2D: FieldElement{0x1b7548c1af8f0, 0x7848c53368116, + 0x1b64e7383de9, 0x109fbb0587c8f, 0x41bb887b726d1}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x34c597c6691ae, + 0x7a150b6990fc4, 0x52beb9d922274, 0x70eed7164861a, 0xa871e070c6a9}, + YMinusX: FieldElement{0x7d44744346be, 0x282b6a564a81d, + 0x4ed80f875236b, 0x6fbbe1d450c50, 0x4eb728c12fcdb}, + XY2D: FieldElement{0x1b5994bbc8989, 0x74b7ba84c0660, + 0x75678f1cdaeb8, 0x23206b0d6f10c, 0x3ee7300f2685d}}, + NielsPoint{YPlusX: FieldElement{0x27947841e7518, + 0x32c7388dae87f, 0x414add3971be9, 0x1850832f0ef1, 0x7d47c6a2cfb89}, + YMinusX: FieldElement{0x255e49e7dd6b7, 0x38c2163d59eba, + 0x3861f2a005845, 0x2e11e4ccbaec9, 0x1381576297912}, + XY2D: FieldElement{0x2d0148ef0d6e0, 0x3522a8de787fb, + 0x2ee055e74f9d2, 0x64038f6310813, 0x148cf58d34c9e}}, + NielsPoint{YPlusX: FieldElement{0x72f7d9ae4756d, + 0x7711e690ffc4a, 0x582a2355b0d16, 0xdccfe885b6b4, 0x278febad4eaea}, + YMinusX: FieldElement{0x492f67934f027, 0x7ded0815528d4, + 0x58461511a6612, 0x5ea2e50de1544, 0x3ff2fa1ebd5db}, + XY2D: FieldElement{0x2681f8c933966, 0x3840521931635, + 0x674f14a308652, 0x3bd9c88a94890, 0x4104dd02fe9c6}}, + NielsPoint{YPlusX: FieldElement{0x14e06db096ab8, + 0x1219c89e6b024, 0x278abd486a2db, 0x240b292609520, 0x165b5a48efca}, + YMinusX: FieldElement{0x2bf5e1124422a, 0x673146756ae56, + 0x14ad99a87e830, 0x1eaca65b080fd, 0x2c863b00afaf5}, + XY2D: FieldElement{0xa474a0846a76, 0x99a5ef981e32, + 0x2a8ae3c4bbfe6, 0x45c34af14832c, 0x591b67d9bffec}}, + NielsPoint{YPlusX: FieldElement{0x1b3719f18b55d, + 0x754318c83d337, 0x27c17b7919797, 0x145b084089b61, 0x489b4f8670301}, + YMinusX: FieldElement{0x70d1c80b49bfa, 0x3d57e7d914625, + 0x3c0722165e545, 0x5e5b93819e04f, 0x3de02ec7ca8f7}, + XY2D: FieldElement{0x2102d3aeb92ef, 0x68c22d50c3a46, + 0x42ea89385894e, 0x75f9ebf55f38c, 0x49f5fbba496cb}}, + NielsPoint{YPlusX: FieldElement{0x5628c1e9c572e, + 0x598b108e822ab, 0x55d8fae29361a, 0xadc8d1a97b28, 0x6a1a6c288675}, + YMinusX: FieldElement{0x49a108a5bcfd4, 0x6178c8e7d6612, + 0x1f03473710375, 0x73a49614a6098, 0x5604a86dcbfa6}, + XY2D: FieldElement{0xd1d47c1764b6, 0x1c08316a2e51, + 0x2b3db45c95045, 0x1634f818d300c, 0x20989e89fe274}}, + NielsPoint{YPlusX: FieldElement{0x4278b85eaec2e, + 0xef59657be2ce, 0x72fd169588770, 0x2e9b205260b30, 0x730b9950f7059}, + YMinusX: FieldElement{0x777fd3a2dcc7f, 0x594a9fb124932, + 0x1f8e80ca15f0, 0x714d13cec3269, 0x403ed1d0ca67}, + XY2D: FieldElement{0x32d35874ec552, 0x1f3048df1b929, + 0x300d73b179b23, 0x6e67be5a37d0b, 0x5bd7454308303}}, + NielsPoint{YPlusX: FieldElement{0x4932115e7792a, + 0x457b9bbb930b8, 0x68f5d8b193226, 0x4164e8f1ed456, 0x5bb7db123067f}, + YMinusX: FieldElement{0x2d19528b24cc2, 0x4ac66b8302ff3, + 0x701c8d9fdad51, 0x6c1b35c5b3727, 0x133a78007380a}, + XY2D: FieldElement{0x1f467c6ca62be, 0x2c4232a5dc12c, + 0x7551dc013b087, 0x690c11b03bcd, 0x740dca6d58f0e}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x28c570478433c, + 0x1d8502873a463, 0x7641e7eded49c, 0x1ecedd54cf571, 0x2c03f5256c2b0}, + YMinusX: FieldElement{0xee0752cfce4e, 0x660dd8116fbe9, + 0x55167130fffeb, 0x1c682b885955c, 0x161d25fa963ea}, + XY2D: FieldElement{0x718757b53a47d, 0x619e18b0f2f21, + 0x5fbdfe4c1ec04, 0x5d798c81ebb92, 0x699468bdbd96b}}, + NielsPoint{YPlusX: FieldElement{0x53de66aa91948, + 0x45f81a599b1b, 0x3f7a8bd214193, 0x71d4da412331a, 0x293e1c4e6c4a2}, + YMinusX: FieldElement{0x72f46f4dafecf, 0x2948ffadef7a3, + 0x11ecdfdf3bc04, 0x3c2e98ffeed25, 0x525219a473905}, + XY2D: FieldElement{0x6134b925112e1, 0x6bb942bb406ed, + 0x70c445c0dde2, 0x411d822c4d7a3, 0x5b605c447f032}}, + NielsPoint{YPlusX: FieldElement{0x1fec6f0e7f04c, + 0x3cebc692c477d, 0x77986a19a95e, 0x6eaaaa1778b0f, 0x2f12fef4cc5ab}, + YMinusX: FieldElement{0x5805920c47c89, 0x1924771f9972c, + 0x38bbddf9fc040, 0x1f7000092b281, 0x24a76dcea8aeb}, + XY2D: FieldElement{0x522b2dfc0c740, 0x7e8193480e148, + 0x33fd9a04341b9, 0x3c863678a20bc, 0x5e607b2518a43}}, + NielsPoint{YPlusX: FieldElement{0x4431ca596cf14, + 0x15da7c801405, 0x3c9b6f8f10b5, 0x346922934017, 0x201f33139e457}, + YMinusX: FieldElement{0x31d8f6cdf1818, 0x1f86c4b144b16, + 0x39875b8d73e9d, 0x2fbf0d9ffa7b3, 0x5067acab6ccdd}, + XY2D: FieldElement{0x27f6b08039d51, 0x4802f8000dfaa, + 0x9692a062c525, 0x1baea91075817, 0x397cba8862460}}, + NielsPoint{YPlusX: FieldElement{0x5c3fbc81379e7, + 0x41bbc255e2f02, 0x6a3f756998650, 0x1297fd4e07c42, 0x771b4022c1e1c}, + YMinusX: FieldElement{0x13093f05959b2, 0x1bd352f2ec618, + 0x75789b88ea86, 0x61d1117ea48b9, 0x2339d320766e6}, + XY2D: FieldElement{0x5d986513a2fa7, 0x63f3a99e11b0f, + 0x28a0ecfd6b26d, 0x53b6835e18d8f, 0x331a189219971}}, + NielsPoint{YPlusX: FieldElement{0x12f3a9d7572af, + 0x10d00e953c4ca, 0x603df116f2f8a, 0x33dc276e0e088, 0x1ac9619ff649a}, + YMinusX: FieldElement{0x66f45fb4f80c6, 0x3cc38eeb9fea2, + 0x107647270db1f, 0x710f1ea740dc8, 0x31167c6b83bdf}, + XY2D: FieldElement{0x33842524b1068, 0x77dd39d30fe45, + 0x189432141a0d0, 0x88fe4eb8c225, 0x612436341f08b}}, + NielsPoint{YPlusX: FieldElement{0x349e31a2d2638, + 0x137a7fa6b16c, 0x681ae92777edc, 0x222bfc5f8dc51, 0x1522aa3178d90}, + YMinusX: FieldElement{0x541db874e898d, 0x62d80fb841b33, + 0x3e6ef027fa97, 0x7a03c9e9633e8, 0x46ebe2309e5ef}, + XY2D: FieldElement{0x2f5369614938, 0x356e5ada20587, + 0x11bc89f6bf902, 0x36746419c8db, 0x45fe70f505243}}, + NielsPoint{YPlusX: FieldElement{0x24920c8951491, + 0x107ec61944c5e, 0x72752e017c01f, 0x122b7dda2e97a, 0x16619f6db57a2}, + YMinusX: FieldElement{0x75a6960c0b8c, 0x6dde1c5e41b49, + 0x42e3f516da341, 0x16a03fda8e79e, 0x428d1623a0e39}, + XY2D: FieldElement{0x74a4401a308fd, 0x6ed4b9558109, + 0x746f1f6a08867, 0x4636f5c6f2321, 0x1d81592d60bd3}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x5b69f7b85c5e8, + 0x17a2d175650ec, 0x4cc3e6dbfc19e, 0x73e1d3873be0e, 0x3a5f6d51b0af8}, + YMinusX: FieldElement{0x68756a60dac5f, 0x55d757b8aec26, + 0x3383df45f80bd, 0x6783f8c9f96a6, 0x20234a7789ecd}, + XY2D: FieldElement{0x20db67178b252, 0x73aa3da2c0eda, + 0x79045c01c70d3, 0x1b37b15251059, 0x7cd682353cffe}}, + NielsPoint{YPlusX: FieldElement{0x5cd6068acf4f3, + 0x3079afc7a74cc, 0x58097650b64b4, 0x47fabac9c4e99, 0x3ef0253b2b2cd}, + YMinusX: FieldElement{0x1a45bd887fab6, 0x65748076dc17c, + 0x5b98000aa11a8, 0x4a1ecc9080974, 0x2838c8863bdc0}, + XY2D: FieldElement{0x3b0cf4a465030, 0x22b8aef57a2d, + 0x2ad0677e925ad, 0x4094167d7457a, 0x21dcb8a606a82}}, + NielsPoint{YPlusX: FieldElement{0x500fabe7731ba, + 0x7cc53c3113351, 0x7cf65fe080d81, 0x3c5d966011ba1, 0x5d840dbf6c6f6}, + YMinusX: FieldElement{0x4468c9d9fc8, 0x5da8554796b8c, + 0x3b8be70950025, 0x6d5892da6a609, 0xbc3d08194a31}, + XY2D: FieldElement{0x6380d309fe18b, 0x4d73c2cb8ee0d, + 0x6b882adbac0b6, 0x36eabdddd4cbe, 0x3a4276232ac19}}, + NielsPoint{YPlusX: FieldElement{0xc172db447ecb, + 0x3f8c505b7a77f, 0x6a857f97f3f10, 0x4fcc0567fe03a, 0x770c9e824e1a}, + YMinusX: FieldElement{0x2432c8a7084fa, 0x47bf73ca8a968, + 0x1639176262867, 0x5e8df4f8010ce, 0x1ff177cea16de}, + XY2D: FieldElement{0x1d99a45b5b5fd, 0x523674f2499ec, + 0xf8fa26182613, 0x58f7398048c98, 0x39f264fd41500}}, + NielsPoint{YPlusX: FieldElement{0x34aabfe097be1, + 0x43bfc03253a33, 0x29bc7fe91b7f3, 0xa761e4844a16, 0x65c621272c35f}, + YMinusX: FieldElement{0x53417dbe7e29c, 0x54573827394f5, + 0x565eea6f650dd, 0x42050748dc749, 0x1712d73468889}, + XY2D: FieldElement{0x389f8ce3193dd, 0x2d424b8177ce5, + 0x73fa0d3440cd, 0x139020cd49e97, 0x22f9800ab19ce}}, + NielsPoint{YPlusX: FieldElement{0x29fdd9a6efdac, + 0x7c694a9282840, 0x6f7cdeee44b3a, 0x55a3207b25cc3, 0x4171a4d38598c}, + YMinusX: FieldElement{0x2368a3e9ef8cb, 0x454aa08e2ac0b, + 0x490923f8fa700, 0x372aa9ea4582f, 0x13f416cd64762}, + XY2D: FieldElement{0x758aa99c94c8c, 0x5f6001700ff44, + 0x7694e488c01bd, 0xd5fde948eed6, 0x508214fa574bd}}, + NielsPoint{YPlusX: FieldElement{0x215bb53d003d6, + 0x1179e792ca8c3, 0x1a0e96ac840a2, 0x22393e2bb3ab6, 0x3a7758a4c86cb}, + YMinusX: FieldElement{0x269153ed6fe4b, 0x72a23aef89840, + 0x52be5299699c, 0x3a5e5ef132316, 0x22f960ec6faba}, + XY2D: FieldElement{0x111f693ae5076, 0x3e3bfaa94ca90, + 0x445799476b887, 0x24a0912464879, 0x5d9fd15f8de7f}}, + NielsPoint{YPlusX: FieldElement{0x44d2aeed7521e, + 0x50865d2c2a7e4, 0x2705b5238ea40, 0x46c70b25d3b97, 0x3bc187fa47eb9}, + YMinusX: FieldElement{0x408d36d63727f, 0x5faf8f6a66062, + 0x2bb892da8de6b, 0x769d4f0c7e2e6, 0x332f35914f8fb}, + XY2D: FieldElement{0x70115ea86c20c, 0x16d88da24ada8, + 0x1980622662adf, 0x501ebbc195a9d, 0x450d81ce906fb}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x4d8961cae743f, + 0x6bdc38c7dba0e, 0x7d3b4a7e1b463, 0x844bdee2adf3, 0x4cbad279663ab}, + YMinusX: FieldElement{0x3b6a1a6205275, 0x2e82791d06dcf, + 0x23d72caa93c87, 0x5f0b7ab68aaf4, 0x2de25d4ba6345}, + XY2D: FieldElement{0x19024a0d71fcd, 0x15f65115f101a, + 0x4e99067149708, 0x119d8d1cba5af, 0x7d7fbcefe2007}}, + NielsPoint{YPlusX: FieldElement{0x45dc5f3c29094, + 0x3455220b579af, 0x70c1631e068a, 0x26bc0630e9b21, 0x4f9cd196dcd8d}, + YMinusX: FieldElement{0x71e6a266b2801, 0x9aae73e2df5d, + 0x40dd8b219b1a3, 0x546fb4517de0d, 0x5975435e87b75}, + XY2D: FieldElement{0x297d86a7b3768, 0x4835a2f4c6332, + 0x70305f434160, 0x183dd014e56ae, 0x7ccdd084387a0}}, + NielsPoint{YPlusX: FieldElement{0x484186760cc93, + 0x7435665533361, 0x2f686336b801, 0x5225446f64331, 0x3593ca848190c}, + YMinusX: FieldElement{0x6422c6d260417, 0x212904817bb94, + 0x5a319deb854f5, 0x7a9d4e060da7d, 0x428bd0ed61d0c}, + XY2D: FieldElement{0x3189a5e849aa7, 0x6acbb1f59b242, + 0x7f6ef4753630c, 0x1f346292a2da9, 0x27398308da2d6}}, + NielsPoint{YPlusX: FieldElement{0x10e4c0a702453, + 0x4daafa37bd734, 0x49f6bdc3e8961, 0x1feffdcecdae6, 0x572c2945492c3}, + YMinusX: FieldElement{0x38d28435ed413, 0x4064f19992858, + 0x7680fbef543cd, 0x1aadd83d58d3c, 0x269597aebe8c3}, + XY2D: FieldElement{0x7c745d6cd30be, 0x27c7755df78ef, + 0x1776833937fa3, 0x5405116441855, 0x7f985498c05bc}}, + NielsPoint{YPlusX: FieldElement{0x615520fbf6363, + 0xb9e9bf74da6a, 0x4fe8308201169, 0x173f76127de43, 0x30f2653cd69b1}, + YMinusX: FieldElement{0x1ce889f0be117, 0x36f6a94510709, + 0x7f248720016b4, 0x1821ed1e1cf91, 0x76c2ec470a31f}, + XY2D: FieldElement{0xc938aac10c85, 0x41b64ed797141, + 0x1beb1c1185e6d, 0x1ed5490600f07, 0x2f1273f159647}}, + NielsPoint{YPlusX: FieldElement{0x8bd755a70bc0, + 0x49e3a885ce609, 0x16585881b5ad6, 0x3c27568d34f5e, 0x38ac1997edc5f}, + YMinusX: FieldElement{0x1fc7c8ae01e11, 0x2094d5573e8e7, + 0x5ca3cbbf549d2, 0x4f920ecc54143, 0x5d9e572ad85b6}, + XY2D: FieldElement{0x6b517a751b13b, 0xcfd370b180cc, + 0x5377925d1f41a, 0x34e56566008a2, 0x22dfcd9cbfe9e}}, + NielsPoint{YPlusX: FieldElement{0x459b4103be0a1, + 0x59a4b3f2d2add, 0x7d734c8bb8eeb, 0x2393cbe594a09, 0xfe9877824cde}, + YMinusX: FieldElement{0x3d2e0c30d0cd9, 0x3f597686671bb, + 0xaa587eb63999, 0xe3c7b592c619, 0x6b2916c05448c}, + XY2D: FieldElement{0x334d10aba913b, 0x45cdb581cfdb, + 0x5e3e0553a8f36, 0x50bb3041effb2, 0x4c303f307ff00}}, + NielsPoint{YPlusX: FieldElement{0x403580dd94500, + 0x48df77d92653f, 0x38a9fe3b349ea, 0xea89850aafe1, 0x416b151ab706a}, + YMinusX: FieldElement{0x23bd617b28c85, 0x6e72ee77d5a61, + 0x1a972ff174dde, 0x3e2636373c60f, 0xd61b8f78b2ab}, + XY2D: FieldElement{0xd7efe9c136b0, 0x1ab1c89640ad5, + 0x55f82aef41f97, 0x46957f317ed0d, 0x191a2af74277e}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x62b434f460efb, + 0x294c6c0fad3fc, 0x68368937b4c0f, 0x5c9f82910875b, 0x237e7dbe00545}, + YMinusX: FieldElement{0x6f74bc53c1431, 0x1c40e5dbbd9c2, + 0x6c8fb9cae5c97, 0x4845c5ce1b7da, 0x7e2e0e450b5cc}, + XY2D: FieldElement{0x575ed6701b430, 0x4d3e17fa20026, + 0x791fc888c4253, 0x2f1ba99078ac1, 0x71afa699b1115}}, + NielsPoint{YPlusX: FieldElement{0x23c1c473b50d6, + 0x3e7671de21d48, 0x326fa5547a1e8, 0x50e4dc25fafd9, 0x731fbc78f89}, + YMinusX: FieldElement{0x66f9b3953b61d, 0x555f4283cccb9, + 0x7dd67fb1960e7, 0x14707a1affed4, 0x21142e9c2b1c}, + XY2D: FieldElement{0xc71848f81880, 0x44bd9d8233c86, + 0x6e8578efe5830, 0x4045b6d7041b5, 0x4c4d6f3347e15}}, + NielsPoint{YPlusX: FieldElement{0x4ddfc988f1970, + 0x4f6173ea365e1, 0x645daf9ae4588, 0x7d43763db623b, 0x38bf9500a88f9}, + YMinusX: FieldElement{0x7eccfc17d1fc9, 0x4ca280782831e, + 0x7b8337db1d7d6, 0x5116def3895fb, 0x193fddaaa7e47}, + XY2D: FieldElement{0x2c93c37e8876f, 0x3431a28c583fa, + 0x49049da8bd879, 0x4b4a8407ac11c, 0x6a6fb99ebf0d4}}, + NielsPoint{YPlusX: FieldElement{0x122b5b6e423c6, + 0x21e50dff1ddd6, 0x73d76324e75c0, 0x588485495418e, 0x136fda9f42c5e}, + YMinusX: FieldElement{0x6c1bb560855eb, 0x71f127e13ad48, + 0x5c6b304905aec, 0x3756b8e889bc7, 0x75f76914a3189}, + XY2D: FieldElement{0x4dfb1a305bdd1, 0x3b3ff05811f29, + 0x6ed62283cd92e, 0x65d1543ec52e1, 0x22183510be8d}}, + NielsPoint{YPlusX: FieldElement{0x2710143307a7f, + 0x3d88fb48bf3ab, 0x249eb4ec18f7a, 0x136115dff295f, 0x1387c441fd404}, + YMinusX: FieldElement{0x766385ead2d14, 0x194f8b06095e, + 0x8478f6823b62, 0x6018689d37308, 0x6a071ce17b806}, + XY2D: FieldElement{0x3c3d187978af8, 0x7afe1c88276ba, + 0x51df281c8ad68, 0x64906bda4245d, 0x3171b26aaf1ed}}, + NielsPoint{YPlusX: FieldElement{0x5b7d8b28a47d1, + 0x2c2ee149e34c1, 0x776f5629afc53, 0x1f4ea50fc49a9, 0x6c514a6334424}, + YMinusX: FieldElement{0x7319097564ca8, 0x1844ebc233525, + 0x21d4543fdeee1, 0x1ad27aaff1bd2, 0x221fd4873cf08}, + XY2D: FieldElement{0x2204f3a156341, 0x537414065a464, + 0x43c0c3bedcf83, 0x5557e706ea620, 0x48daa596fb924}}, + NielsPoint{YPlusX: FieldElement{0x61d5dc84c9793, + 0x47de83040c29e, 0x189deb26507e7, 0x4d4e6fadc479a, 0x58c837fa0e8a7}, + YMinusX: FieldElement{0x28e665ca59cc7, 0x165c715940dd9, + 0x785f3aa11c95, 0x57b98d7e38469, 0x676dd6fccad84}, + XY2D: FieldElement{0x1688596fc9058, 0x66f6ad403619f, + 0x4d759a87772ef, 0x7856e6173bea4, 0x1c4f73f2c6a57}}, + NielsPoint{YPlusX: FieldElement{0x6706efc7c3484, + 0x6987839ec366d, 0x731f95cf7f26, 0x3ae758ebce4bc, 0x70459adb7daf6}, + YMinusX: FieldElement{0x24fbd305fa0bb, 0x40a98cc75a1cf, + 0x78ce1220a7533, 0x6217a10e1c197, 0x795ac80d1bf64}, + XY2D: FieldElement{0x1db4991b42bb3, 0x469605b994372, + 0x631e3715c9a58, 0x7e9cfefcf728f, 0x5fe162848ce21}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x1852d5d7cb208, + 0x60d0fbe5ce50f, 0x5a1e246e37b75, 0x51aee05ffd590, 0x2b44c043677da}, + YMinusX: FieldElement{0x1214fe194961a, 0xe1ae39a9e9cb, + 0x543c8b526f9f7, 0x119498067e91d, 0x4789d446fc917}, + XY2D: FieldElement{0x487ab074eb78e, 0x1d33b5e8ce343, + 0x13e419feb1b46, 0x2721f565de6a4, 0x60c52eef2bb9a}}, + NielsPoint{YPlusX: FieldElement{0x3c5c27cae6d11, + 0x36a9491956e05, 0x124bac9131da6, 0x3b6f7de202b5d, 0x70d77248d9b66}, + YMinusX: FieldElement{0x589bc3bfd8bf1, 0x6f93e6aa3416b, + 0x4c0a3d6c1ae48, 0x55587260b586a, 0x10bc9c312ccfc}, + XY2D: FieldElement{0x2e84b3ec2a05b, 0x69da2f03c1551, + 0x23a174661a67b, 0x209bca289f238, 0x63755bd3a976f}}, + NielsPoint{YPlusX: FieldElement{0x7101897f1acb7, + 0x3d82cb77b07b8, 0x684083d7769f5, 0x52b28472dce07, 0x2763751737c52}, + YMinusX: FieldElement{0x7a03e2ad10853, 0x213dcc6ad36ab, + 0x1a6e240d5bdd6, 0x7c24ffcf8fedf, 0xd8cc1c48bc16}, + XY2D: FieldElement{0x402d36eb419a9, 0x7cef68c14a052, + 0xf1255bc2d139, 0x373e7d431186a, 0x70c2dd8a7ad16}}, + NielsPoint{YPlusX: FieldElement{0x4967db8ed7e13, + 0x15aeed02f523a, 0x6149591d094bc, 0x672f204c17006, 0x32b8613816a53}, + YMinusX: FieldElement{0x194509f6fec0e, 0x528d8ca31acac, + 0x7826d73b8b9fa, 0x24acb99e0f9b3, 0x2e0fac6363948}, + XY2D: FieldElement{0x7f7bee448cd64, 0x4e10f10da0f3c, + 0x3936cb9ab20e9, 0x7a0fc4fea6cd0, 0x4179215c735a4}}, + NielsPoint{YPlusX: FieldElement{0x633b9286bcd34, + 0x6cab3badb9c95, 0x74e387edfbdfa, 0x14313c58a0fd9, 0x31fa85662241c}, + YMinusX: FieldElement{0x94e7d7dced2a, 0x68fa738e118e, + 0x41b640a5fee2b, 0x6bb709df019d4, 0x700344a30cd99}, + XY2D: FieldElement{0x26c422e3622f4, 0xf3066a05b5f0, + 0x4e2448f0480a6, 0x244cde0dbf095, 0x24bb2312a9952}}, + NielsPoint{YPlusX: FieldElement{0xc2af5f85c6b, + 0x609f4cf2883f, 0x6e86eb5a1ca13, 0x68b44a2efccd1, 0xd1d2af9ffeb5}, + YMinusX: FieldElement{0xed1732de67c3, 0x308c369291635, + 0x33ef348f2d250, 0x4475ea1a1bb, 0xfee3e871e188}, + XY2D: FieldElement{0x28aa132621edf, 0x42b244caf353b, + 0x66b064cc2e08a, 0x6bb20020cbdd3, 0x16acd79718531}}, + NielsPoint{YPlusX: FieldElement{0x1c6c57887b6ad, + 0x5abf21fd7592b, 0x50bd41253867a, 0x3800b71273151, 0x164ed34b18161}, + YMinusX: FieldElement{0x772af2d9b1d3d, 0x6d486448b4e5b, + 0x2ce58dd8d18a8, 0x1849f67503c8b, 0x123e0ef6b9302}, + XY2D: FieldElement{0x6d94c192fe69a, 0x5475222a2690f, + 0x693789d86b8b3, 0x1f5c3bdfb69dc, 0x78da0fc61073f}}, + NielsPoint{YPlusX: FieldElement{0x780f1680c3a94, + 0x2a35d3cfcd453, 0x5e5cdc7ddf8, 0x6ee888078ac24, 0x54aa4b316b38}, + YMinusX: FieldElement{0x15d28e52bc66a, 0x30e1e0351cb7e, + 0x30a2f74b11f8c, 0x39d120cd7de03, 0x2d25deeb256b1}, + XY2D: FieldElement{0x468d19267cb8, 0x38cdca9b5fbf9, + 0x1bbb05c2ca1e2, 0x3b015758e9533, 0x134610a6ab7da}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x265e777d1f515, + 0xf1f54c1e39a5, 0x2f01b95522646, 0x4fdd8db9dde6d, 0x654878cba97cc}, + YMinusX: FieldElement{0x38ec78df6b0fe, 0x13caebea36a22, + 0x5ebc6e54e5f6a, 0x32804903d0eb8, 0x2102fdba2b20d}, + XY2D: FieldElement{0x6e405055ce6a1, 0x5024a35a532d3, + 0x1f69054daf29d, 0x15d1d0d7a8bd5, 0xad725db29ecb}}, + NielsPoint{YPlusX: FieldElement{0x7bc0c9b056f85, + 0x51cfebffaffd8, 0x44abbe94df549, 0x7ecbbd7e33121, 0x4f675f5302399}, + YMinusX: FieldElement{0x267b1834e2457, 0x6ae19c378bb88, + 0x7457b5ed9d512, 0x3280d783d05fb, 0x4aefcffb71a03}, + XY2D: FieldElement{0x536360415171e, 0x2313309077865, + 0x251444334afbc, 0x2b0c3853756e8, 0xbccbb72a2a86}}, + NielsPoint{YPlusX: FieldElement{0x55e4c50fe1296, + 0x5fdd13efc30d, 0x1c0c6c380e5ee, 0x3e11de3fb62a8, 0x6678fd69108f3}, + YMinusX: FieldElement{0x6962feab1a9c8, 0x6aca28fb9a30b, + 0x56db7ca1b9f98, 0x39f58497018dd, 0x4024f0ab59d6b}, + XY2D: FieldElement{0x6fa31636863c2, 0x10ae5a67e42b0, + 0x27abbf01fda31, 0x380a7b9e64fbc, 0x2d42e2108ead4}}, + NielsPoint{YPlusX: FieldElement{0x17b0d0f537593, + 0x16263c0c9842e, 0x4ab827e4539a4, 0x6370ddb43d73a, 0x420bf3a79b423}, + YMinusX: FieldElement{0x5131594dfd29b, 0x3a627e98d52fe, + 0x1154041855661, 0x19175d09f8384, 0x676b2608b8d2d}, + XY2D: FieldElement{0xba651c5b2b47, 0x5862363701027, + 0xc4d6c219c6db, 0xf03dff8658de, 0x745d2ffa9c0cf}}, + NielsPoint{YPlusX: FieldElement{0x6df5721d34e6a, + 0x4f32f767a0c06, 0x1d5abeac76e20, 0x41ce9e104e1e4, 0x6e15be54c1dc}, + YMinusX: FieldElement{0x25a1e2bc9c8bd, 0x104c8f3b037ea, + 0x405576fa96c98, 0x2e86a88e3876f, 0x1ae23ceb960cf}, + XY2D: FieldElement{0x25d871932994a, 0x6b9d63b560b6e, + 0x2df2814c8d472, 0xfbbee20aa4ed, 0x58ded861278ec}}, + NielsPoint{YPlusX: FieldElement{0x35ba8b6c2c9a8, + 0x1dea58b3185bf, 0x4b455cd23bbbe, 0x5ec19c04883f8, 0x8ba696b531d5}, + YMinusX: FieldElement{0x73793f266c55c, 0xb988a9c93b02, + 0x9b0ea32325db, 0x37cae71c17c5e, 0x2ff39de85485f}, + XY2D: FieldElement{0x53eeec3efc57a, 0x2fa9fe9022efd, + 0x699c72c138154, 0x72a751ebd1ff8, 0x120633b4947cf}}, + NielsPoint{YPlusX: FieldElement{0x531474912100a, + 0x5afcdf7c0d057, 0x7a9e71b788ded, 0x5ef708f3b0c88, 0x7433be3cb393}, + YMinusX: FieldElement{0x4987891610042, 0x79d9d7f5d0172, + 0x3c293013b9ec4, 0xc2b85f39caca, 0x35d30a99b4d59}, + XY2D: FieldElement{0x144c05ce997f4, 0x4960b8a347fef, + 0x1da11f15d74f7, 0x54fac19c0fead, 0x2d873ede7af6d}}, + NielsPoint{YPlusX: FieldElement{0x202e14e5df981, + 0x2ea02bc3eb54c, 0x38875b2883564, 0x1298c513ae9dd, 0x543618a01600}, + YMinusX: FieldElement{0x2316443373409, 0x5de95503b22af, + 0x699201beae2df, 0x3db5849ff737a, 0x2e773654707fa}, + XY2D: FieldElement{0x2bdf4974c23c1, 0x4b3b9c8d261bd, + 0x26ae8b2a9bc28, 0x3068210165c51, 0x4b1443362d079}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x454e91c529ccb, + 0x24c98c6bf72cf, 0x486594c3d89a, 0x7ae13a3d7fa3c, 0x17038418eaf66}, + YMinusX: FieldElement{0x4b7c7b66e1f7a, 0x4bea185efd998, + 0x4fabc711055f8, 0x1fb9f7836fe38, 0x582f446752da6}, + XY2D: FieldElement{0x17bd320324ce4, 0x51489117898c6, + 0x1684d92a0410b, 0x6e4d90f78c5a7, 0xc2a1c4bcda28}}, + NielsPoint{YPlusX: FieldElement{0x4814869bd6945, + 0x7b7c391a45db8, 0x57316ac35b641, 0x641e31de9096a, 0x5a6a9b30a314d}, + YMinusX: FieldElement{0x5c7d06f1f0447, 0x7db70f80b3a49, + 0x6cb4a3ec89a78, 0x43be8ad81397d, 0x7c558bd1c6f64}, + XY2D: FieldElement{0x41524d396463d, 0x1586b449e1a1d, + 0x2f17e904aed8a, 0x7e1d2861d3c8e, 0x404a5ca0afba}}, + NielsPoint{YPlusX: FieldElement{0x49e1b2a416fd1, + 0x51c6a0b316c57, 0x575a59ed71bdc, 0x74c021a1fec1e, 0x39527516e7f8e}, + YMinusX: FieldElement{0x740070aa743d6, 0x16b64cbdd1183, + 0x23f4b7b32eb43, 0x319aba58235b3, 0x46395bfdcadd9}, + XY2D: FieldElement{0x7db2d1a5d9a9c, 0x79a200b85422f, + 0x355bfaa71dd16, 0xb77ea5f78aa, 0x76579a29e822d}}, + NielsPoint{YPlusX: FieldElement{0x4b51352b434f2, + 0x1327bd01c2667, 0x434d73b60c8a1, 0x3e0daa89443ba, 0x2c514bb2a277}, + YMinusX: FieldElement{0x68e7e49c02a17, 0x45795346fe8b6, + 0x89306c8f3546, 0x6d89f6b2f88f6, 0x43a384dc9e05b}, + XY2D: FieldElement{0x3d5da8bf1b645, 0x7ded6a96a6d09, + 0x6c3494fee2f4d, 0x2c989c8b6bd4, 0x1160920961548}}, + NielsPoint{YPlusX: FieldElement{0x5616369b4dcd, + 0x4ecab86ac6f47, 0x3c60085d700b2, 0x213ee10dfcea, 0x2f637d7491e6e}, + YMinusX: FieldElement{0x5166929dacfaa, 0x190826b31f689, + 0x4f55567694a7d, 0x705f4f7b1e522, 0x351e125bc5698}, + XY2D: FieldElement{0x49b461af67bbe, 0x75915712c3a96, + 0x69a67ef580c0d, 0x54d38ef70cffc, 0x7f182d06e7ce2}}, + NielsPoint{YPlusX: FieldElement{0x54b728e217522, + 0x69a90971b0128, 0x51a40f2a963a3, 0x10be9ac12a6bf, 0x44acc043241c5}, + YMinusX: FieldElement{0x48e64ab0168ec, 0x2a2bdb8a86f4f, + 0x7343b6b2d6929, 0x1d804aa8ce9a3, 0x67d4ac8c343e9}, + XY2D: FieldElement{0x56bbb4f7a5777, 0x29230627c238f, + 0x5ad1a122cd7fb, 0xdea56e50e364, 0x556d1c8312ad7}}, + NielsPoint{YPlusX: FieldElement{0x6756b11be821, + 0x462147e7bb03e, 0x26519743ebfe0, 0x782fc59682ab5, 0x97abe38cc8c7}, + YMinusX: FieldElement{0x740e30c8d3982, 0x7c2b47f4682fd, + 0x5cd91b8c7dc1c, 0x77fa790f9e583, 0x746c6c6d1d824}, + XY2D: FieldElement{0x1c9877ea52da4, 0x2b37b83a86189, + 0x733af49310da5, 0x25e81161c04fb, 0x577e14a34bee8}}, + NielsPoint{YPlusX: FieldElement{0x6cebebd4dd72b, + 0x340c1e442329f, 0x32347ffd1a93f, 0x14a89252cbbe0, 0x705304b8fb009}, + YMinusX: FieldElement{0x268ac61a73b0a, 0x206f234bebe1c, + 0x5b403a7cbebe8, 0x7a160f09f4135, 0x60fa7ee96fd78}, + XY2D: FieldElement{0x51d354d296ec6, 0x7cbf5a63b16c7, + 0x2f50bb3cf0c14, 0x1feb385cac65a, 0x21398e0ca1635}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0xaaf9b4b75601, + 0x26b91b5ae44f3, 0x6de808d7ab1c8, 0x6a769675530b0, 0x1bbfb284e98f7}, + YMinusX: FieldElement{0x5058a382b33f3, 0x175a91816913e, + 0x4f6cdb96b8ae8, 0x17347c9da81d2, 0x5aa3ed9d95a23}, + XY2D: FieldElement{0x777e9c7d96561, 0x28e58f006ccac, + 0x541bbbb2cac49, 0x3e63282994cec, 0x4a07e14e5e895}}, + NielsPoint{YPlusX: FieldElement{0x358cdc477a49b, + 0x3cc88fe02e481, 0x721aab7f4e36b, 0x408cc9469953, 0x50af7aed84afa}, + YMinusX: FieldElement{0x412cb980df999, 0x5e78dd8ee29dc, + 0x171dff68c575d, 0x2015dd2f6ef49, 0x3f0bac391d313}, + XY2D: FieldElement{0x7de0115f65be5, 0x4242c21364dc9, + 0x6b75b64a66098, 0x33c0102c085, 0x1921a316baebd}}, + NielsPoint{YPlusX: FieldElement{0x2ad9ad9f3c18b, + 0x5ec1638339aeb, 0x5703b6559a83b, 0x3fa9f4d05d612, 0x7b049deca062c}, + YMinusX: FieldElement{0x22f7edfb870fc, 0x569eed677b128, + 0x30937dcb0a5af, 0x758039c78ea1b, 0x6458df41e273a}, + XY2D: FieldElement{0x3e37a35444483, 0x661fdb7d27b99, + 0x317761dd621e4, 0x7323c30026189, 0x6093dccbc2950}}, + NielsPoint{YPlusX: FieldElement{0x6eebe6084034b, + 0x6cf01f70a8d7b, 0xb41a54c6670a, 0x6c84b99bb55db, 0x6e3180c98b647}, + YMinusX: FieldElement{0x39a8585e0706d, 0x3167ce72663fe, + 0x63d14ecdb4297, 0x4be21dcf970b8, 0x57d1ea084827a}, + XY2D: FieldElement{0x2b6e7a128b071, 0x5b27511755dcf, + 0x8584c2930565, 0x68c7bda6f4159, 0x363e999ddd97b}}, + NielsPoint{YPlusX: FieldElement{0x48dce24baec6, + 0x2b75795ec05e3, 0x3bfa4c5da6dc9, 0x1aac8659e371e, 0x231f979bc6f9b}, + YMinusX: FieldElement{0x43c135ee1fc4, 0x2a11c9919f2d5, + 0x6334cc25dbacd, 0x295da17b400da, 0x48ee9b78693a0}, + XY2D: FieldElement{0x1de4bcc2af3c6, 0x61fc411a3eb86, + 0x53ed19ac12ec0, 0x209dbc6b804e0, 0x79bfa9b08792}}, + NielsPoint{YPlusX: FieldElement{0x1ed80a2d54245, + 0x70efec72a5e79, 0x42151d42a822d, 0x1b5ebb6d631e8, 0x1ef4fb1594706}, + YMinusX: FieldElement{0x3a51da300df4, 0x467b52b561c72, + 0x4d5920210e590, 0xca769e789685, 0x38c77f684817}, + XY2D: FieldElement{0x65ee65b167bec, 0x52da19b850a9, + 0x408665656429, 0x7ab39596f9a4c, 0x575ee92a4a0bf}}, + NielsPoint{YPlusX: FieldElement{0x6bc450aa4d801, + 0x4f4a6773b0ba8, 0x6241b0b0ebc48, 0x40d9c4f1d9315, 0x200a1e7e382f5}, + YMinusX: FieldElement{0x80908a182fcf, 0x532913b7ba98, + 0x3dccf78c385c3, 0x68002dd5eaba9, 0x43d4e7112cd3f}, + XY2D: FieldElement{0x5b967eaf93ac5, 0x360acca580a31, + 0x1c65fd5c6f262, 0x71c7f15c2ecab, 0x50eca52651e4}}, + NielsPoint{YPlusX: FieldElement{0x4397660e668ea, + 0x7c2a75692f2f5, 0x3b29e7e6c66ef, 0x72ba658bcda9a, 0x6151c09fa131a}, + YMinusX: FieldElement{0x31ade453f0c9c, 0x3dfee07737868, + 0x611ecf7a7d411, 0x2637e6cbd64f6, 0x4b0ee6c21c58f}, + XY2D: FieldElement{0x55c0dfdf05d96, 0x405569dcf475e, + 0x5c5c277498bb, 0x18588d95dc389, 0x1fef24fa800f0}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x2aff530976b86, + 0xd85a48c0845a, 0x796eb963642e0, 0x60bee50c4b626, 0x28005fe6c8340}, + YMinusX: FieldElement{0x653fb1aa73196, 0x607faec8306fa, + 0x4e85ec83e5254, 0x9f56900584fd, 0x544d49292fc86}, + XY2D: FieldElement{0x7ba9f34528688, 0x284a20fb42d5d, + 0x3652cd9706ffe, 0x6fd7baddde6b3, 0x72e472930f316}}, + NielsPoint{YPlusX: FieldElement{0x3f635d32a7627, + 0xcbecacde00fe, 0x3411141eaa936, 0x21c1e42f3cb94, 0x1fee7f000fe06}, + YMinusX: FieldElement{0x5208c9781084f, 0x16468a1dc24d2, + 0x7bf780ac540a8, 0x1a67eced75301, 0x5a9d2e8c2733a}, + XY2D: FieldElement{0x305da03dbf7e5, 0x1228699b7aeca, + 0x12a23b2936bc9, 0x2a1bda56ae6e9, 0xf94051ee040}}, + NielsPoint{YPlusX: FieldElement{0x793bb07af9753, + 0x1e7b6ecd4fafd, 0x2c7b1560fb43, 0x2296734cc5fb7, 0x47b7ffd25dd40}, + YMinusX: FieldElement{0x56b23c3d330b2, 0x37608e360d1a6, + 0x10ae0f3c8722e, 0x86d9b618b637, 0x7d79c7e8beab}, + XY2D: FieldElement{0x3fb9cbc08dd12, 0x75c3dd85370ff, + 0x47f06fe2819ac, 0x5db06ab9215ed, 0x1c3520a35ea64}}, + NielsPoint{YPlusX: FieldElement{0x6f40216bc059, + 0x3a2579b0fd9b5, 0x71c26407eec8c, 0x72ada4ab54f0b, 0x38750c3b66d12}, + YMinusX: FieldElement{0x253a6bccba34a, 0x427070433701a, + 0x20b8e58f9870e, 0x337c861db00cc, 0x1c3d05775d0ee}, + XY2D: FieldElement{0x6f1409422e51a, 0x7856bbece2d25, + 0x13380a72f031c, 0x43e1080a7f3ba, 0x621e2c7d3304}}, + NielsPoint{YPlusX: FieldElement{0x61796b0dbf0f3, + 0x73c2f9c32d6f5, 0x6aa8ed1537ebe, 0x74e92c91838f4, 0x5d8e589ca1002}, + YMinusX: FieldElement{0x60cc8259838d, 0x38d3f35b95f3, + 0x56078c243a923, 0x2de3293241bb2, 0x7d6097bd3a}, + XY2D: FieldElement{0x71d950842a94b, 0x46b11e5c7d817, + 0x5478bbecb4f0d, 0x7c3054b0a1c5d, 0x1583d7783c1cb}}, + NielsPoint{YPlusX: FieldElement{0x34704cc9d28c7, + 0x3dee598b1f200, 0x16e1c98746d9e, 0x4050b7095afdf, 0x4958064e83c55}, + YMinusX: FieldElement{0x6a2ef5da27ae1, 0x28aace02e9d9d, + 0x2459e965f0e8, 0x7b864d3150933, 0x252a5f2e81ed8}, + XY2D: FieldElement{0x94265066e80d, 0xa60f918d61a5, + 0x444bf7f30fde, 0x1c40da9ed3c06, 0x79c170bd843b}}, + NielsPoint{YPlusX: FieldElement{0x6cd50c0d5d056, + 0x5b7606ae779ba, 0x70fbd226bdda1, 0x5661e53391ff9, 0x6768c0d7317b8}, + YMinusX: FieldElement{0x6ece464fa6fff, 0x3cc40bca460a0, + 0x6e3a90afb8d0c, 0x5801abca11228, 0x6dec05e34ac9f}, + XY2D: FieldElement{0x625e5f155c1b3, 0x4f32f6f723296, + 0x5ac980105efce, 0x17a61165eee36, 0x51445e14ddcd5}}, + NielsPoint{YPlusX: FieldElement{0x147ab2bbea455, + 0x1f240f2253126, 0xc3de9e314e89, 0x21ea5a4fca45f, 0x12e990086e4fd}, + YMinusX: FieldElement{0x2b4b3b144951, 0x5688977966aea, + 0x18e176e399ffd, 0x2e45c5eb4938b, 0x13186f31e3929}, + XY2D: FieldElement{0x496b37fdfbb2e, 0x3c2439d5f3e21, + 0x16e60fe7e6a4d, 0x4d7ef889b621d, 0x77b2e3f05d3e9}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x639c12ddb0a4, + 0x6180490cd7ab3, 0x3f3918297467c, 0x74568be1781ac, 0x7a195152e095}, + YMinusX: FieldElement{0x7a9c59c2ec4de, 0x7e9f09e79652d, + 0x6a3e422f22d86, 0x2ae8e3b836c8b, 0x63b795fc7ad32}, + XY2D: FieldElement{0x68f02389e5fc8, 0x59f1bc877506, + 0x504990e410cec, 0x9bd7d0feaee2, 0x3e8fe83d032f0}}, + NielsPoint{YPlusX: FieldElement{0x4c8de8efd13c, + 0x1c67c06e6210e, 0x183378f7f146a, 0x64352ceaed289, 0x22d60899a6258}, + YMinusX: FieldElement{0x315b90570a294, 0x60ce108a925f1, + 0x6eff61253c909, 0x3ef0e2d70b0, 0x75ba3b797fac4}, + XY2D: FieldElement{0x1dbc070cdd196, 0x16d8fb1534c47, + 0x500498183fa2a, 0x72f59c423de75, 0x904d07b87779}}, + NielsPoint{YPlusX: FieldElement{0x22d6648f940b9, + 0x197a5a1873e86, 0x207e4c41a54bc, 0x5360b3b4bd6d0, 0x6240aacebaf72}, + YMinusX: FieldElement{0x61fd4ddba919c, 0x7d8e991b55699, + 0x61b31473cc76c, 0x7039631e631d6, 0x43e2143fbc1dd}, + XY2D: FieldElement{0x4749c5ba295a0, 0x37946fa4b5f06, + 0x724c5ab5a51f1, 0x65633789dd3f3, 0x56bdaf238db40}}, + NielsPoint{YPlusX: FieldElement{0xd36cc19d3bb2, + 0x6ec4470d72262, 0x6853d7018a9ae, 0x3aa3e4dc2c8eb, 0x3aa31507e1e5}, + YMinusX: FieldElement{0x2b9e3f53533eb, 0x2add727a806c5, + 0x56955c8ce15a3, 0x18c4f070a290e, 0x1d24a86d83741}, + XY2D: FieldElement{0x47648ffd4ce1f, 0x60a9591839e9d, + 0x424d5f38117ab, 0x42cc46912c10e, 0x43b261dc9aeb4}}, + NielsPoint{YPlusX: FieldElement{0x13d8b6c951364, + 0x4c0017e8f632a, 0x53e559e53f9c4, 0x4b20146886eea, 0x2b4d5e242940}, + YMinusX: FieldElement{0x31e1988bb79bb, 0x7b82f46b3bcab, + 0xf7a8ce827b41, 0x5e15816177130, 0x326055cf5b276}, + XY2D: FieldElement{0x155cb28d18df2, 0xc30d9ca11694, + 0x2090e27ab3119, 0x208624e7a49b6, 0x27a6c809ae5d3}}, + NielsPoint{YPlusX: FieldElement{0x4270ac43d6954, + 0x2ed4cd95659a5, 0x75c0db37528f9, 0x2ccbcfd2c9234, 0x221503603d8c2}, + YMinusX: FieldElement{0x6ebcd1f0db188, 0x74ceb4b7d1174, + 0x7d56168df4f5c, 0xbf79176fd18a, 0x2cb67174ff60a}, + XY2D: FieldElement{0x6cdf9390be1d0, 0x8e519c7e2b3d, + 0x253c3d2a50881, 0x21b41448e333d, 0x7b1df4b73890f}}, + NielsPoint{YPlusX: FieldElement{0x6221807f8f58c, + 0x3fa92813a8be5, 0x6da98c38d5572, 0x1ed95554468f, 0x68698245d352e}, + YMinusX: FieldElement{0x2f2e0b3b2a224, 0xc56aa22c1c92, + 0x5fdec39f1b278, 0x4c90af5c7f106, 0x61fcef2658fc5}, + XY2D: FieldElement{0x15d852a18187a, 0x270dbb59afb76, + 0x7db120bcf92ab, 0xe7a25d714087, 0x46cf4c473daf0}}, + NielsPoint{YPlusX: FieldElement{0x46ea7f1498140, + 0x70725690a8427, 0xa73ae9f079fb, 0x2dd924461c62b, 0x1065aae50d8cc}, + YMinusX: FieldElement{0x525ed9ec4e5f9, 0x22d20660684c, + 0x7972b70397b68, 0x7a03958d3f965, 0x29387bcd14eb5}, + XY2D: FieldElement{0x44525df200d57, 0x2d7f94ce94385, + 0x60d00c170ecb7, 0x38b0503f3d8f0, 0x69a198e64f1ce}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x14434dcc5caed, + 0x2c7909f667c20, 0x61a839d1fb576, 0x4f23800cabb76, 0x25b2697bd267f}, + YMinusX: FieldElement{0x2b2e0d91a78bc, 0x3990a12ccf20c, + 0x141c2e11f2622, 0xdfcefaa53320, 0x7369e6a92493a}, + XY2D: FieldElement{0x73ffb13986864, 0x3282bb8f713ac, + 0x49ced78f297ef, 0x6697027661def, 0x1420683db54e4}}, + NielsPoint{YPlusX: FieldElement{0x6bb6fc1cc5ad0, + 0x532c8d591669d, 0x1af794da86c33, 0xe0e9d86d24d3, 0x31e83b4161d08}, + YMinusX: FieldElement{0xbd1e249dd197, 0xbcb1820568f, + 0x2eab1718830d4, 0x396fd816997e6, 0x60b63bebf508a}, + XY2D: FieldElement{0xc7129e062b4f, 0x1e526415b12fd, + 0x461a0fd27923d, 0x18badf670a5b7, 0x55cf1eb62d550}}, + NielsPoint{YPlusX: FieldElement{0x6b5e37df58c52, + 0x3bcf33986c60e, 0x44fb8835ceae7, 0x99dec18e71a4, 0x1a56fbaa62ba0}, + YMinusX: FieldElement{0x1101065c23d58, 0x5aa1290338b0f, + 0x3157e9e2e7421, 0xea712017d489, 0x669a656457089}, + XY2D: FieldElement{0x66b505c9dc9ec, 0x774ef86e35287, + 0x4d1d944c0955e, 0x52e4c39d72b20, 0x13c4836799c58}}, + NielsPoint{YPlusX: FieldElement{0x4fb6a5d8bd080, + 0x58ae34908589b, 0x3954d977baf13, 0x413ea597441dc, 0x50bdc87dc8e5b}, + YMinusX: FieldElement{0x25d465ab3e1b9, 0xf8fe27ec2847, + 0x2d6e6dbf04f06, 0x3038cfc1b3276, 0x66f80c93a637b}, + XY2D: FieldElement{0x537836edfe111, 0x2be02357b2c0d, + 0x6dcee58c8d4f8, 0x2d732581d6192, 0x1dd56444725fd}}, + NielsPoint{YPlusX: FieldElement{0x7e60008bac89a, + 0x23d5c387c1852, 0x79e5df1f533a8, 0x2e6f9f1c5f0cf, 0x3a3a450f63a30}, + YMinusX: FieldElement{0x47ff83362127d, 0x8e39af82b1f4, + 0x488322ef27dab, 0x1973738a2a1a4, 0xe645912219f7}, + XY2D: FieldElement{0x72f31d8394627, 0x7bd294a200f1, + 0x665be00e274c6, 0x43de8f1b6368b, 0x318c8d9393a9a}}, + NielsPoint{YPlusX: FieldElement{0x69e29ab1dd398, + 0x30685b3c76bac, 0x565cf37f24859, 0x57b2ac28efef9, 0x509a41c325950}, + YMinusX: FieldElement{0x45d032afffe19, 0x12fe49b6cde4e, + 0x21663bc327cf1, 0x18a5e4c69f1dd, 0x224c7c679a1d5}, + XY2D: FieldElement{0x6edca6f925e9, 0x68c8363e677b8, + 0x60cfa25e4fbcf, 0x1c4c17609404e, 0x5bff02328a11}}, + NielsPoint{YPlusX: FieldElement{0x1a0dd0dc512e4, + 0x10894bf5fcd10, 0x52949013f9c37, 0x1f50fba4735c7, 0x576277cdee01a}, + YMinusX: FieldElement{0x2137023cae00b, 0x15a3599eb26c6, + 0x687221512b3c, 0x253cb3a0824e9, 0x780b8cc3fa2a4}, + XY2D: FieldElement{0x38abc234f305f, 0x7a280bbc103de, + 0x398a836695dfe, 0x3d0af41528a1a, 0x5ff418726271b}}, + NielsPoint{YPlusX: FieldElement{0x347e813b69540, + 0x76864c21c3cbb, 0x1e049dbcd74a8, 0x5b4d60f93749c, 0x29d4db8ca0a0c}, + YMinusX: FieldElement{0x6080c1789db9d, 0x4be7cef1ea731, + 0x2f40d769d8080, 0x35f7d4c44a603, 0x106a03dc25a96}, + XY2D: FieldElement{0x50aaf333353d0, 0x4b59a613cbb35, + 0x223dfc0e19a76, 0x77d1e2bb2c564, 0x4ab38a51052cb}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x7d1ef5fddc09c, + 0x7beeaebb9dad9, 0x58d30ba0acfb, 0x5cd92eab5ae90, 0x3041c6bb04ed2}, + YMinusX: FieldElement{0x42b256768d593, 0x2e88459427b4f, + 0x2b3876630701, 0x34878d405eae5, 0x29cdd1adc088a}, + XY2D: FieldElement{0x2f2f9d956e148, 0x6b3e6ad65c1fe, + 0x5b00972b79e5d, 0x53d8d234c5daf, 0x104bbd6814049}}, + NielsPoint{YPlusX: FieldElement{0x59a5fd67ff163, + 0x3a998ead0352b, 0x83c95fa4af9a, 0x6fadbfc01266f, 0x204f2a20fb072}, + YMinusX: FieldElement{0xfd3168f1ed67, 0x1bb0de7784a3e, + 0x34bcb78b20477, 0xa4a26e2e2182, 0x5be8cc57092a7}, + XY2D: FieldElement{0x43b3d30ebb079, 0x357aca5c61902, + 0x5b570c5d62455, 0x30fb29e1e18c7, 0x2570fb17c2791}}, + NielsPoint{YPlusX: FieldElement{0x6a9550bb8245a, + 0x511f20a1a2325, 0x29324d7239bee, 0x3343cc37516c4, 0x241c5f91de018}, + YMinusX: FieldElement{0x2367f2cb61575, 0x6c39ac04d87df, + 0x6d4958bd7e5bd, 0x566f4638a1532, 0x3dcb65ea53030}, + XY2D: FieldElement{0x172940de6caa, 0x6045b2e67451b, + 0x56c07463efcb3, 0x728b6bfe6e91, 0x8420edd5fcdf}}, + NielsPoint{YPlusX: FieldElement{0xc34e04f410ce, + 0x344edc0d0a06b, 0x6e45486d84d6d, 0x44e2ecb3863f5, 0x4d654f321db8}, + YMinusX: FieldElement{0x720ab8362fa4a, 0x29c4347cdd9bf, + 0xe798ad5f8463, 0x4fef18bcb0bfe, 0xd9a53efbc176}, + XY2D: FieldElement{0x5c116ddbdb5d5, 0x6d1b4bba5abcf, + 0x4d28a48a5537a, 0x56b8e5b040b99, 0x4a7a4f2618991}}, + NielsPoint{YPlusX: FieldElement{0x3b291af372a4b, + 0x60e3028fe4498, 0x2267bca4f6a09, 0x719eec242b243, 0x4a96314223e0e}, + YMinusX: FieldElement{0x718025fb15f95, 0x68d6b8371fe94, + 0x3804448f7d97c, 0x42466fe784280, 0x11b50c4cddd31}, + XY2D: FieldElement{0x274408a4ffd6, 0x7d382aedb34dd, + 0x40acfc9ce385d, 0x628bb99a45b1e, 0x4f4bce4dce6bc}}, + NielsPoint{YPlusX: FieldElement{0x2616ec49d0b6f, + 0x1f95d8462e61c, 0x1ad3e9b9159c6, 0x79ba475a04df9, 0x3042cee561595}, + YMinusX: FieldElement{0x7ce5ae2242584, 0x2d25eb153d4e3, + 0x3a8f3d09ba9c9, 0xf3690d04eb8e, 0x73fcdd14b71c0}, + XY2D: FieldElement{0x67079449bac41, 0x5b79c4621484f, + 0x61069f2156b8d, 0xeb26573b10af, 0x389e740c9a9ce}}, + NielsPoint{YPlusX: FieldElement{0x578f6570eac28, + 0x644f2339c3937, 0x66e47b7956c2c, 0x34832fe1f55d0, 0x25c425e5d6263}, + YMinusX: FieldElement{0x4b3ae34dcb9ce, 0x47c691a15ac9f, + 0x318e06e5d400c, 0x3c422d9f83eb1, 0x61545379465a6}, + XY2D: FieldElement{0x606a6f1d7de6e, 0x4f1c0c46107e7, + 0x229b1dcfbe5d8, 0x3acc60a7b1327, 0x6539a08915484}}, + NielsPoint{YPlusX: FieldElement{0x4dbd414bb4a19, + 0x7930849f1dbb8, 0x329c5a466caf0, 0x6c824544feb9b, 0xf65320ef019b}, + YMinusX: FieldElement{0x21f74c3d2f773, 0x24b88d08bd3a, + 0x6e678cf054151, 0x43631272e747c, 0x11c5e4aac5cd1}, + XY2D: FieldElement{0x6d1b1cafde0c6, 0x462c76a303a90, + 0x3ca4e693cff9b, 0x3952cd45786fd, 0x4cabc7bdec330}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x7788f3f78d289, + 0x5942809b3f811, 0x5973277f8c29c, 0x10f93bc5fe67, 0x7ee498165acb2}, + YMinusX: FieldElement{0x69624089c0a2e, 0x75fc8e70473, + 0x13e84ab1d2313, 0x2c10bedf6953b, 0x639b93f0321c8}, + XY2D: FieldElement{0x508e39111a1c3, 0x290120e912f7a, + 0x1cbf464acae43, 0x15373e9576157, 0xedf493c85b60}}, + NielsPoint{YPlusX: FieldElement{0x7c4d284764113, + 0x7fefebf06acec, 0x39afb7a824100, 0x1b48e47e7fd65, 0x4c00c54d1dfa}, + YMinusX: FieldElement{0x48158599b5a68, 0x1fd75bc41d5d9, + 0x2d9fc1fa95d3c, 0x7da27f20eba11, 0x403b92e3019d4}, + XY2D: FieldElement{0x22f818b465cf8, 0x342901dff09b8, + 0x31f595dc683cd, 0x37a57745fd682, 0x355bb12ab2617}}, + NielsPoint{YPlusX: FieldElement{0x1dac75a8c7318, + 0x3b679d5423460, 0x6b8fcb7b6400e, 0x6c73783be5f9d, 0x7518eaf8e052a}, + YMinusX: FieldElement{0x664cc7493bbf4, 0x33d94761874e3, + 0x179e1796f613, 0x1890535e2867d, 0xf9b8132182ec}, + XY2D: FieldElement{0x59c41b7f6c32, 0x79e8706531491, + 0x6c747643cb582, 0x2e20c0ad494e4, 0x47c3871bbb175}}, + NielsPoint{YPlusX: FieldElement{0x65d50c85066b0, + 0x6167453361f7c, 0x6ba3818bb312, 0x6aff29baa7522, 0x8fea02ce8d48}, + YMinusX: FieldElement{0x4539771ec4f48, 0x7b9318badca28, + 0x70f19afe016c5, 0x4ee7bb1608d23, 0xb89b8576469}, + XY2D: FieldElement{0x5dd7668deead0, 0x4096d0ba47049, + 0x6275997219114, 0x29bda8a67e6ae, 0x473829a74f75d}}, + NielsPoint{YPlusX: FieldElement{0x1533aad3902c9, + 0x1dde06b11e47b, 0x784bed1930b77, 0x1c80a92b9c867, 0x6c668b4d44e4d}, + YMinusX: FieldElement{0x2da754679c418, 0x3164c31be105a, + 0x11fac2b98ef5f, 0x35a1aaf779256, 0x2078684c4833c}, + XY2D: FieldElement{0xcf217a78820c, 0x65024e7d2e769, + 0x23bb5efdda82a, 0x19fd4b632d3c6, 0x7411a6054f8a4}}, + NielsPoint{YPlusX: FieldElement{0x2e53d18b175b4, + 0x33e7254204af3, 0x3bcd7d5a1c4c5, 0x4c7c22af65d0f, 0x1ec9a872458c3}, + YMinusX: FieldElement{0x59d32b99dc86d, 0x6ac075e22a9ac, + 0x30b9220113371, 0x27fd9a638966e, 0x7c136574fb813}, + XY2D: FieldElement{0x6a4d400a2509b, 0x41791056971c, + 0x655d5866e075c, 0x2302bf3e64df8, 0x3add88a5c7cd6}}, + NielsPoint{YPlusX: FieldElement{0x298d459393046, + 0x30bfecb3d90b8, 0x3d9b8ea3df8d6, 0x3900e96511579, 0x61ba1131a406a}, + YMinusX: FieldElement{0x15770b635dcf2, 0x59ecd83f79571, + 0x2db461c0b7fbd, 0x73a42a981345f, 0x249929fccc879}, + XY2D: FieldElement{0xa0f116959029, 0x5974fd7b1347a, + 0x1e0cc1c08edad, 0x673bdf8ad1f13, 0x5620310cbbd8e}}, + NielsPoint{YPlusX: FieldElement{0x6b5f477e285d6, + 0x4ed91ec326cc8, 0x6d6537503a3fd, 0x626d3763988d5, 0x7ec846f3658ce}, + YMinusX: FieldElement{0x193434934d643, 0xd4a2445eaa51, + 0x7d0708ae76fe0, 0x39847b6c3c7e1, 0x37676a2a4d9d9}, + XY2D: FieldElement{0x68f3f1da22ec7, 0x6ed8039a2736b, + 0x2627ee04c3c75, 0x6ea90a647e7d1, 0x6daaf723399b9}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x304bfacad8ea2, + 0x502917d108b07, 0x43176ca6dd0f, 0x5d5158f2c1d84, 0x2b5449e58eb3b}, + YMinusX: FieldElement{0x27562eb3dbe47, 0x291d7b4170be7, + 0x5d1ca67dfa8e1, 0x2a88061f298a2, 0x1304e9e71627d}, + XY2D: FieldElement{0x14d26adc9cfe, 0x7f1691ba16f13, + 0x5e71828f06eac, 0x349ed07f0fffc, 0x4468de2d7c2dd}}, + NielsPoint{YPlusX: FieldElement{0x2d8c6f86307ce, + 0x6286ba1850973, 0x5e9dcb08444d4, 0x1a96a543362b2, 0x5da6427e63247}, + YMinusX: FieldElement{0x3355e9419469e, 0x1847bb8ea8a37, + 0x1fe6588cf9b71, 0x6b1c9d2db6b22, 0x6cce7c6ffb44b}, + XY2D: FieldElement{0x4c688deac22ca, 0x6f775c3ff0352, + 0x565603ee419bb, 0x6544456c61c46, 0x58f29abfe79f2}}, + NielsPoint{YPlusX: FieldElement{0x264bf710ecdf6, + 0x708c58527896b, 0x42ceae6c53394, 0x4381b21e82b6a, 0x6af93724185b4}, + YMinusX: FieldElement{0x6cfab8de73e68, 0x3e6efced4bd21, + 0x56609500dbe, 0x71b7824ad85df, 0x577629c4a7f41}, + XY2D: FieldElement{0x24509c6a888, 0x2696ab12e6644, + 0xcca27f4b80d8, 0xc7c1f11b119e, 0x701f25bb0caec}}, + NielsPoint{YPlusX: FieldElement{0xf6d97cbec113, + 0x4ce97fb7c93a3, 0x139835a11281b, 0x728907ada9156, 0x720a5bc050955}, + YMinusX: FieldElement{0xb0f8e4616ced, 0x1d3c4b50fb875, + 0x2f29673dc0198, 0x5f4b0f1830ffa, 0x2e0c92bfbdc40}, + XY2D: FieldElement{0x709439b805a35, 0x6ec48557f8187, + 0x8a4d1ba13a2c, 0x76348a0bf9ae, 0xe9b9cbb144ef}}, + NielsPoint{YPlusX: FieldElement{0x69bd55db1beee, + 0x6e14e47f731bd, 0x1a35e47270eac, 0x66f225478df8e, 0x366d44191cfd3}, + YMinusX: FieldElement{0x2d48ffb5720ad, 0x57b7f21a1df77, + 0x5550effba0645, 0x5ec6a4098a931, 0x221104eb3f337}, + XY2D: FieldElement{0x41743f2bc8c14, 0x796b0ad8773c7, + 0x29fee5cbb689b, 0x122665c178734, 0x4167a4e6bc593}}, + NielsPoint{YPlusX: FieldElement{0x62665f8ce8fee, + 0x29d101ac59857, 0x4d93bbba59ffc, 0x17b7897373f17, 0x34b33370cb7ed}, + YMinusX: FieldElement{0x39d2876f62700, 0x1cecd1d6c87, + 0x7f01a11747675, 0x2350da5a18190, 0x7938bb7e22552}, + XY2D: FieldElement{0x591ee8681d6cc, 0x39db0b4ea79b8, + 0x202220f380842, 0x2f276ba42e0ac, 0x1176fc6e2dfe6}}, + NielsPoint{YPlusX: FieldElement{0xe28949770eb8, + 0x5559e88147b72, 0x35e1e6e63ef30, 0x35b109aa7ff6f, 0x1f6a3e54f2690}, + YMinusX: FieldElement{0x76cd05b9c619b, 0x69654b0901695, + 0x7a53710b77f27, 0x79a1ea7d28175, 0x8fc3a4c677d5}, + XY2D: FieldElement{0x4c199d30734ea, 0x6c622cb9acc14, + 0x5660a55030216, 0x68f1199f11fb, 0x4f2fad0116b90}}, + NielsPoint{YPlusX: FieldElement{0x4d91db73bb638, + 0x55f82538112c5, 0x6d85a279815de, 0x740b7b0cd9cf9, 0x3451995f2944e}, + YMinusX: FieldElement{0x6b24194ae4e54, 0x2230afded8897, + 0x23412617d5071, 0x3d5d30f35969b, 0x445484a4972ef}, + XY2D: FieldElement{0x2fcd09fea7d7c, 0x296126b9ed22a, + 0x4a171012a05b2, 0x1db92c74d5523, 0x10b89ca604289}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x141be5a45f06e, + 0x5adb38becaea7, 0x3fd46db41f2bb, 0x6d488bbb5ce39, 0x17d2d1d9ef0d4}, + YMinusX: FieldElement{0x147499718289c, 0xa48a67e4c7ab, + 0x30fbc544bafe3, 0xc701315fe58a, 0x20b878d577b75}, + XY2D: FieldElement{0x2af18073f3e6a, 0x33aea420d24fe, + 0x298008bf4ff94, 0x3539171db961e, 0x72214f63cc65c}}, + NielsPoint{YPlusX: FieldElement{0x5b7b9f43b29c9, + 0x149ea31eea3b3, 0x4be7713581609, 0x2d87960395e98, 0x1f24ac855a154}, + YMinusX: FieldElement{0x37f405307a693, 0x2e5e66cf2b69c, + 0x5d84266ae9c53, 0x5e4eb7de853b9, 0x5fdf48c58171c}, + XY2D: FieldElement{0x608328e9505aa, 0x22182841dc49a, + 0x3ec96891d2307, 0x2f363fff22e03, 0xba739e2ae39}}, + NielsPoint{YPlusX: FieldElement{0x426f5ea88bb26, + 0x33092e77f75c8, 0x1a53940d819e7, 0x1132e4f818613, 0x72297de7d518d}, + YMinusX: FieldElement{0x698de5c8790d6, 0x268b8545beb25, + 0x6d2648b96fedf, 0x47988ad1db07c, 0x3283a3e67ad7}, + XY2D: FieldElement{0x41dc7be0cb939, 0x1b16c66100904, + 0xa24c20cbc66d, 0x4a2e9efe48681, 0x5e1296846271}}, + NielsPoint{YPlusX: FieldElement{0x7bbc8242c4550, + 0x59a06103b35b7, 0x7237e4af32033, 0x726421ab3537a, 0x78cf25d38258c}, + YMinusX: FieldElement{0x2eeb32d9c495a, 0x79e25772f9750, + 0x6d747833bbf23, 0x6cdd816d5d749, 0x39c00c9c13698}, + XY2D: FieldElement{0x66b8e31489d68, 0x573857e10e2b5, + 0x13be816aa1472, 0x41964d3ad4bf8, 0x6b52076b3ff}}, + NielsPoint{YPlusX: FieldElement{0x37e16b9ce082d, + 0x1882f57853eb9, 0x7d29eacd01fc5, 0x2e76a59b5e715, 0x7de2e9561a9f7}, + YMinusX: FieldElement{0xcfe19d95781c, 0x312cc621c453c, + 0x145ace6da077c, 0x912bef9ce9b8, 0x4d57e3443bc76}, + XY2D: FieldElement{0xd4f4b6a55ecb, 0x7ebb0bb733bce, + 0x7ba6a05200549, 0x4f6ede4e22069, 0x6b2a90af1a602}}, + NielsPoint{YPlusX: FieldElement{0x3f3245bb2d80a, + 0xe5f720f36efd, 0x3b9cccf60c06d, 0x84e323f37926, 0x465812c8276c2}, + YMinusX: FieldElement{0x3f4fc9ae61e97, 0x3bc07ebfa2d24, + 0x3b744b55cd4a0, 0x72553b25721f3, 0x5fd8f4e9d12d3}, + XY2D: FieldElement{0x3beb22a1062d9, 0x6a7063b82c9a8, + 0xa5a35dc197ed, 0x3c80c06a53def, 0x5b32c2b1cb16}}, + NielsPoint{YPlusX: FieldElement{0x4a42c7ad58195, + 0x5c8667e799eff, 0x2e5e74c850a1, 0x3f0db614e869a, 0x31771a4856730}, + YMinusX: FieldElement{0x5eccd24da8fd, 0x580bbfdf07918, + 0x7e73586873c6a, 0x74ceddf77f93e, 0x3b5556a37b471}, + XY2D: FieldElement{0xc524e14dd482, 0x283457496c656, + 0xad6bcfb6cd45, 0x375d1e8b02414, 0x4fc079d27a733}}, + NielsPoint{YPlusX: FieldElement{0x48b440c86c50d, + 0x139929cca3b86, 0xf8f2e44cdf2f, 0x68432117ba6b2, 0x241170c2bae3c}, + YMinusX: FieldElement{0x138b089bf2f7f, 0x4a05bfd34ea39, + 0x203914c925ef5, 0x7497fffe04e3c, 0x124567cecaf98}, + XY2D: FieldElement{0x1ab860ac473b4, 0x5c0227c86a7ff, + 0x71b12bfc24477, 0x6a573a83075, 0x3f8612966c870}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0xfcfa36048d13, + 0x66e7133bbb383, 0x64b42a8a45676, 0x4ea6e4f9a85cf, 0x26f57eee878a1}, + YMinusX: FieldElement{0x20cc9782a0dde, 0x65d4e3070aab3, + 0x7bc8e31547736, 0x9ebfb1432d98, 0x504aa77679736}, + XY2D: FieldElement{0x32cd55687efb1, 0x4448f5e2f6195, + 0x568919d460345, 0x34c2e0ad1a27, 0x4041943d9dba3}}, + NielsPoint{YPlusX: FieldElement{0x17743a26caadd, + 0x48c9156f9c964, 0x7ef278d1e9ad0, 0xce58ea7bd01, 0x12d931429800d}, + YMinusX: FieldElement{0xeeba43ebcc96, 0x384dd5395f878, + 0x1df331a35d272, 0x207ecfd4af70e, 0x1420a1d976843}, + XY2D: FieldElement{0x67799d337594f, 0x1647548f6018, + 0x57fce5578f145, 0x9220c142a71, 0x1b4f92314359a}}, + NielsPoint{YPlusX: FieldElement{0x73030a49866b1, + 0x2442be90b2679, 0x77bd3d8947dcf, 0x1fb55c1552028, 0x5ff191d56f9a2}, + YMinusX: FieldElement{0x4109d89150951, 0x225bd2d2d47cb, + 0x57cc080e73bea, 0x6d71075721fcb, 0x239b572a7f132}, + XY2D: FieldElement{0x6d433ac2d9068, 0x72bf930a47033, + 0x64facf4a20ead, 0x365f7a2b9402a, 0x20c526a758f3}}, + NielsPoint{YPlusX: FieldElement{0x1ef59f042cc89, + 0x3b1c24976dd26, 0x31d665cb16272, 0x28656e470c557, 0x452cfe0a5602c}, + YMinusX: FieldElement{0x34f89ed8dbbc, 0x73b8f948d8ef3, + 0x786c1d323caab, 0x43bd4a9266e51, 0x2aacc4615313}, + XY2D: FieldElement{0xf7a0647877df, 0x4e1cc0f93f0d4, + 0x7ec4726ef1190, 0x3bdd58bf512f8, 0x4cfb7d7b304b8}}, + NielsPoint{YPlusX: FieldElement{0x699c29789ef12, + 0x63beae321bc50, 0x325c340adbb35, 0x562e1a1e42bf6, 0x5b1d4cbc434d3}, + YMinusX: FieldElement{0x43d6cb89b75fe, 0x3338d5b900e56, + 0x38d327d531a53, 0x1b25c61d51b9f, 0x14b4622b39075}, + XY2D: FieldElement{0x32615cc0a9f26, 0x57711b99cb6df, + 0x5a69c14e93c38, 0x6e88980a4c599, 0x2f98f71258592}}, + NielsPoint{YPlusX: FieldElement{0x2ae444f54a701, + 0x615397afbc5c2, 0x60d7783f3f8fb, 0x2aa675fc486ba, 0x1d8062e9e7614}, + YMinusX: FieldElement{0x4a74cb50f9e56, 0x531d1c2640192, + 0xc03d9d6c7fd2, 0x57ccd156610c1, 0x3a6ae249d806a}, + XY2D: FieldElement{0x2da85a9907c5a, 0x6b23721ec4caf, + 0x4d2d3a4683aa2, 0x7f9c6870efdef, 0x298b8ce8aef25}}, + NielsPoint{YPlusX: FieldElement{0x272ea0a2165de, + 0x68179ef3ed06f, 0x4e2b9c0feac1e, 0x3ee290b1b63bb, 0x6ba6271803a7d}, + YMinusX: FieldElement{0x27953eff70cb2, 0x54f22ae0ec552, + 0x29f3da92e2724, 0x242ca0c22bd18, 0x34b8a8404d5ce}, + XY2D: FieldElement{0x6ecb583693335, 0x3ec76bfdfb84d, + 0x2c895cf56a04f, 0x6355149d54d52, 0x71d62bdd465e1}}, + NielsPoint{YPlusX: FieldElement{0x5b5dab1f75ef5, + 0x1e2d60cbeb9a5, 0x527c2175dfe57, 0x59e8a2b8ff51f, 0x1c333621262b2}, + YMinusX: FieldElement{0x3cc28d378df80, 0x72141f4968ca6, + 0x407696bdb6d0d, 0x5d271b22ffcfb, 0x74d5f317f3172}, + XY2D: FieldElement{0x7e55467d9ca81, 0x6a5653186f50d, + 0x6b188ece62df1, 0x4c66d36844971, 0x4aebcc4547e9d}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x8d9e7354b610, + 0x26b750b6dc168, 0x162881e01acc9, 0x7966df31d01a5, 0x173bd9ddc9a1d}, + YMinusX: FieldElement{0x71b276d01c9, 0xb0d8918e025e, + 0x75beea79ee2eb, 0x3c92984094db8, 0x5d88fbf95a3db}, + XY2D: FieldElement{0xf1efe5872df, 0x5da872318256a, + 0x59ceb81635960, 0x18cf37693c764, 0x6e1cd13b19ea}}, + NielsPoint{YPlusX: FieldElement{0x3af629e5b0353, + 0x204f1a088e8e5, 0x10efc9ceea82e, 0x589863c2fa34b, 0x7f3a6a1a8d837}, + YMinusX: FieldElement{0xad516f166f23, 0x263f56d57c81a, + 0x13422384638ca, 0x1331ff1af0a50, 0x3080603526e16}, + XY2D: FieldElement{0x644395d3d800b, 0x2b9203dbedefc, + 0x4b18ce656a355, 0x3f3466bc182c, 0x30d0fded2e513}}, + NielsPoint{YPlusX: FieldElement{0x4971e68b84750, + 0x52ccc9779f396, 0x3e904ae8255c8, 0x4ecae46f39339, 0x4615084351c58}, + YMinusX: FieldElement{0x14d1af21233b3, 0x1de1989b39c0b, + 0x52669dc6f6f9e, 0x43434b28c3fc7, 0xa9214202c099}, + XY2D: FieldElement{0x19c0aeb9a02e, 0x1a2c06995d792, + 0x664cbb1571c44, 0x6ff0736fa80b2, 0x3bca0d2895ca5}}, + NielsPoint{YPlusX: FieldElement{0x8eb69ecc01bf, + 0x5b4c8912df38d, 0x5ea7f8bc2f20e, 0x120e516caafaf, 0x4ea8b4038df28}, + YMinusX: FieldElement{0x31bc3c5d62a4, 0x7d9fe0f4c081e, + 0x43ed51467f22c, 0x1e6cc0c1ed109, 0x5631deddae8f1}, + XY2D: FieldElement{0x5460af1cad202, 0xb4919dd0655d, + 0x7c4697d18c14c, 0x231c890bba2a4, 0x24ce0930542ca}}, + NielsPoint{YPlusX: FieldElement{0x7a155fdf30b85, + 0x1c6c6e5d487f9, 0x24be1134bdc5a, 0x1405970326f32, 0x549928a7324f4}, + YMinusX: FieldElement{0x90f5fd06c106, 0x6abb1021e43fd, + 0x232bcfad711a0, 0x3a5c13c047f37, 0x41d4e3c28a06d}, + XY2D: FieldElement{0x632a763ee1a2e, 0x6fa4bffbd5e4d, + 0x5fd35a6ba4792, 0x7b55e1de99de8, 0x491b66dec0dcf}}, + NielsPoint{YPlusX: FieldElement{0x4a8ed0da64a1, + 0x5ecfc45096ebe, 0x5edee93b488b2, 0x5b3c11a51bc8f, 0x4cf6b8b0b7018}, + YMinusX: FieldElement{0x5b13dc7ea32a7, 0x18fc2db73131e, + 0x7e3651f8f57e3, 0x25656055fa965, 0x8f338d0c85ee}, + XY2D: FieldElement{0x3a821991a73bd, 0x3be6418f5870, + 0x1ddc18eac9ef0, 0x54ce09e998dc2, 0x530d4a82eb078}}, + NielsPoint{YPlusX: FieldElement{0x173456c9abf9e, + 0x7892015100dad, 0x33ee14095fecb, 0x6ad95d67a0964, 0xdb3e7e00cbfb}, + YMinusX: FieldElement{0x43630e1f94825, 0x4d1956a6b4009, + 0x213fe2df8b5e0, 0x5ce3a41191e6, 0x65ea753f10177}, + XY2D: FieldElement{0x6fc3ee2096363, 0x7ec36b96d67ac, + 0x510ec6a0758b1, 0xed87df022109, 0x2a4ec1921e1a}}, + NielsPoint{YPlusX: FieldElement{0x6162f1cf795f, + 0x324ddcafe5eb9, 0x18d5e0463218, 0x7e78b9092428e, 0x36d12b5dec067}, + YMinusX: FieldElement{0x6259a3b24b8a2, 0x188b5f4170b9c, + 0x681c0dee15deb, 0x4dfe665f37445, 0x3d143c5112780}, + XY2D: FieldElement{0x5279179154557, 0x39f8f0741424d, + 0x45e6eb357923d, 0x42c9b5edb746f, 0x2ef517885ba82}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x6bffb305b2f51, + 0x5b112b2d712dd, 0x35774974fe4e2, 0x4af87a96e3a3, 0x57968290bb3a0}, + YMinusX: FieldElement{0x7974e8c58aedc, 0x7757e083488c6, + 0x601c62ae7bc8b, 0x45370c2ecab74, 0x2f1b78fab143a}, + XY2D: FieldElement{0x2b8430a20e101, 0x1a49e1d88fee3, + 0x38bbb47ce4d96, 0x1f0e7ba84d437, 0x7dc43e35dc2aa}}, + NielsPoint{YPlusX: FieldElement{0x2a5c273e9718, + 0x32bc9dfb28b4f, 0x48df4f8d5db1a, 0x54c87976c028f, 0x44fb81d82d50}, + YMinusX: FieldElement{0x66665887dd9c3, 0x629760a6ab0b2, + 0x481e6c7243e6c, 0x97e37046fc77, 0x7ef72016758cc}, + XY2D: FieldElement{0x718c5a907e3d9, 0x3b9c98c6b383b, + 0x6ed255eccdc, 0x6976538229a59, 0x7f79823f9c30d}}, + NielsPoint{YPlusX: FieldElement{0x41ff068f587ba, + 0x1c00a191bcd53, 0x7b56f9c209e25, 0x3781e5fccaabe, 0x64a9b0431c06d}, + YMinusX: FieldElement{0x4d239a3b513e8, 0x29723f51b1066, + 0x642f4cf04d9c3, 0x4da095aa09b7a, 0xa4e0373d784d}, + XY2D: FieldElement{0x3d6a15b7d2919, 0x41aa75046a5d6, + 0x691751ec2d3da, 0x23638ab6721c4, 0x71a7d0ace183}}, + NielsPoint{YPlusX: FieldElement{0x4355220e14431, + 0xe1362a283981, 0x2757cd8359654, 0x2e9cd7ab10d90, 0x7c69bcf761775}, + YMinusX: FieldElement{0x72daac887ba0b, 0xb7f4ac5dda60, + 0x3bdda2c0498a4, 0x74e67aa180160, 0x2c3bcc7146ea7}, + XY2D: FieldElement{0xd7eb04e8295f, 0x4a5ea1e6fa0fe, + 0x45e635c436c60, 0x28ef4a8d4d18b, 0x6f5a9a7322aca}}, + NielsPoint{YPlusX: FieldElement{0x1d4eba3d944be, + 0x100f15f3dce5, 0x61a700e367825, 0x5922292ab3d23, 0x2ab9680ee8d3}, + YMinusX: FieldElement{0x1000c2f41c6c5, 0x219fdf737174, + 0x314727f127de7, 0x7e5277d23b81e, 0x494e21a2e147a}, + XY2D: FieldElement{0x48a85dde50d9a, 0x1c1f734493df4, + 0x47bdb64866889, 0x59a7d048f8eec, 0x6b5d76cbea46b}}, + NielsPoint{YPlusX: FieldElement{0x141171e782522, + 0x6806d26da7c1f, 0x3f31d1bc79ab9, 0x9f20459f5168, 0x16fb869c03dd3}, + YMinusX: FieldElement{0x7556cec0cd994, 0x5eb9a03b7510a, + 0x50ad1dd91cb71, 0x1aa5780b48a47, 0xae333f685277}, + XY2D: FieldElement{0x6199733b60962, 0x69b157c266511, + 0x64740f893f1ca, 0x3aa408fbf684, 0x3f81e38b8f70d}}, + NielsPoint{YPlusX: FieldElement{0x37f355f17c824, + 0x7ae85334815b, 0x7e3abddd2e48f, 0x61eeabe1f45e5, 0xad3e2d34cded}, + YMinusX: FieldElement{0x10fcc7ed9affe, 0x4248cb0e96ff2, + 0x4311c115172e2, 0x4c9d41cbf6925, 0x50510fc104f50}, + XY2D: FieldElement{0x40fc5336e249d, 0x3386639fb2de1, + 0x7bbf871d17b78, 0x75f796b7e8004, 0x127c158bf0fa1}}, + NielsPoint{YPlusX: FieldElement{0x28fc4ae51b974, + 0x26e89bfd2dbd4, 0x4e122a07665cf, 0x7cab1203405c3, 0x4ed82479d167d}, + YMinusX: FieldElement{0x17c422e9879a2, 0x28a5946c8fec3, + 0x53ab32e912b77, 0x7b44da09fe0a5, 0x354ef87d07ef4}, + XY2D: FieldElement{0x3b52260c5d975, 0x79d6836171fdc, + 0x7d994f140d4bb, 0x1b6c404561854, 0x302d92d205392}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x46fb6e4e0f177, + 0x53497ad5265b7, 0x1ebdba01386fc, 0x302f0cb36a3c, 0xedc5f5eb426d}, + YMinusX: FieldElement{0x3c1a2bca4283d, 0x23430c7bb2f02, + 0x1a3ea1bb58bc2, 0x7265763de5c61, 0x10e5d3b76f1ca}, + XY2D: FieldElement{0x3bfd653da8e67, 0x584953ec82a8a, + 0x55e288fa7707b, 0x5395fc3931d81, 0x45b46c51361cb}}, + NielsPoint{YPlusX: FieldElement{0x54ddd8a7fe3e4, + 0x2cecc41c619d3, 0x43a6562ac4d91, 0x4efa5aca7bdd9, 0x5c1c0aef32122}, + YMinusX: FieldElement{0x2abf314f7fa1, 0x391d19e8a1528, + 0x6a2fa13895fc7, 0x9d8eddeaa591, 0x2177bfa36dcb7}, + XY2D: FieldElement{0x1bbcfa79db8f, 0x3d84beb3666e1, + 0x20c921d812204, 0x2dd843d3b32ce, 0x4ae619387d8ab}}, + NielsPoint{YPlusX: FieldElement{0x17e44985bfb83, + 0x54e32c626cc22, 0x96412ff38118, 0x6b241d61a246a, 0x75685abe5ba43}, + YMinusX: FieldElement{0x3f6aa5344a32e, 0x69683680f11bb, + 0x4c3581f623aa, 0x701af5875cba5, 0x1a00d91b17bf3}, + XY2D: FieldElement{0x60933eb61f2b2, 0x5193fe92a4dd2, + 0x3d995a550f43e, 0x3556fb93a883d, 0x135529b623b0e}}, + NielsPoint{YPlusX: FieldElement{0x716bce22e83fe, + 0x33d0130b83eb8, 0x952abad0afac, 0x309f64ed31b8a, 0x5972ea051590a}, + YMinusX: FieldElement{0xdbd7add1d518, 0x119f823e2231e, + 0x451d66e5e7de2, 0x500c39970f838, 0x79b5b81a65ca3}, + XY2D: FieldElement{0x4ac20dc8f7811, 0x29589a9f501fa, + 0x4d810d26a6b4a, 0x5ede00d96b259, 0x4f7e9c95905f3}}, + NielsPoint{YPlusX: FieldElement{0x443d355299fe, + 0x39b7d7d5aee39, 0x692519a2f34ec, 0x6e4404924cf78, 0x1942eec4a144a}, + YMinusX: FieldElement{0x74bbc5781302e, 0x73135bb81ec4c, + 0x7ef671b61483c, 0x7264614ccd729, 0x31993ad92e638}, + XY2D: FieldElement{0x45319ae234992, 0x2219d47d24fb5, + 0x4f04488b06cf6, 0x53aaa9e724a12, 0x2a0a65314ef9c}}, + NielsPoint{YPlusX: FieldElement{0x61acd3c1c793a, + 0x58b46b78779e6, 0x3369aacbe7af2, 0x509b0743074d4, 0x55dc39b6dea1}, + YMinusX: FieldElement{0x7937ff7f927c2, 0xc2fa14c6a5b6, + 0x556bddb6dd07c, 0x6f6acc179d108, 0x4cf6e218647c2}, + XY2D: FieldElement{0x1227cc28d5bb6, 0x78ee9bff57623, + 0x28cb2241f893a, 0x25b541e3c6772, 0x121a307710aa2}}, + NielsPoint{YPlusX: FieldElement{0x1713ec77483c9, + 0x6f70572d5facb, 0x25ef34e22ff81, 0x54d944f141188, 0x527bb94a6ced3}, + YMinusX: FieldElement{0x35d5e9f034a97, 0x126069785bc9b, + 0x5474ec7854ff0, 0x296a302a348ca, 0x333fc76c7a40e}, + XY2D: FieldElement{0x5992a995b482e, 0x78dc707002ac7, + 0x5936394d01741, 0x4fba4281aef17, 0x6b89069b20a7a}}, + NielsPoint{YPlusX: FieldElement{0x2fa8cb5c7db77, + 0x718e6982aa810, 0x39e95f81a1a1b, 0x5e794f3646cfb, 0x473d308a7639}, + YMinusX: FieldElement{0x2a0416270220d, 0x75f248b69d025, + 0x1cbbc16656a27, 0x5b9ffd6e26728, 0x23bc2103aa73e}, + XY2D: FieldElement{0x6792603589e05, 0x248db9892595d, + 0x6a53cad2d08, 0x20d0150f7ba73, 0x102f73bfde043}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x4dae0b5511c9a, + 0x5257fffe0d456, 0x54108d1eb2180, 0x96cc0f9baefa, 0x3f6bd725da4ea}, + YMinusX: FieldElement{0xb9ab7f5745c6, 0x5caf0f8d21d63, + 0x7debea408ea2b, 0x9edb93896d16, 0x36597d25ea5c0}, + XY2D: FieldElement{0x58d7b106058ac, 0x3cdf8d20bee69, + 0xa4cb765015e, 0x36832337c7cc9, 0x7b7ecc19da60d}}, + NielsPoint{YPlusX: FieldElement{0x64a51a77cfa9b, + 0x29cf470ca0db5, 0x4b60b6e0898d9, 0x55d04ddffe6c7, 0x3bedc661bf5c}, + YMinusX: FieldElement{0x2373c695c690d, 0x4c0c8520dcf18, + 0x384af4b7494b9, 0x4ab4a8ea22225, 0x4235ad7601743}, + XY2D: FieldElement{0xcb0d078975f5, 0x292313e530c4b, + 0x38dbb9124a509, 0x350d0655a11f1, 0xe7ce2b0cdf06}}, + NielsPoint{YPlusX: FieldElement{0x6fedfd94b70f9, + 0x2383f9745bfd4, 0x4beae27c4c301, 0x75aa4416a3f3f, 0x615256138aece}, + YMinusX: FieldElement{0x4643ac48c85a3, 0x6878c2735b892, + 0x3a53523f4d877, 0x3a504ed8bee9d, 0x666e0a5d8fb46}, + XY2D: FieldElement{0x3f64e4870cb0d, 0x61548b16d6557, + 0x7a261773596f3, 0x7724d5f275d3a, 0x7f0bc810d514d}}, + NielsPoint{YPlusX: FieldElement{0x49dad737213a0, + 0x745dee5d31075, 0x7b1a55e7fdbe2, 0x5ba988f176ea1, 0x1d3a907ddec5a}, + YMinusX: FieldElement{0x6ba426f4136f, 0x3cafc0606b720, + 0x518f0a2359cda, 0x5fae5e46feca7, 0xd1f8dbcf8eed}, + XY2D: FieldElement{0x693313ed081dc, 0x5b0a366901742, + 0x40c872ca4ca7e, 0x6f18094009e01, 0x11b44a31bf}}, + NielsPoint{YPlusX: FieldElement{0x61f696a0aa75c, + 0x38b0a57ad42ca, 0x1e59ab706fdc9, 0x1308d46ebfcd, 0x63d988a2d2851}, + YMinusX: FieldElement{0x7a06c3fc66c0c, 0x1c9bac1ba47fb, + 0x23935c575038e, 0x3f0bd71c59c13, 0x3ac48d916e835}, + XY2D: FieldElement{0x20753afbd232e, 0x71fbb1ed06002, + 0x39cae47a4af3a, 0x337c0b34d9c2, 0x33fad52b2368a}}, + NielsPoint{YPlusX: FieldElement{0x4c8d0c422cfe8, + 0x760b4275971a5, 0x3da95bc1cad3d, 0xf151ff5b7376, 0x3cc355ccb90a7}, + YMinusX: FieldElement{0x649c6c5e41e16, 0x60667eee6aa80, + 0x4179d182be190, 0x653d9567e6979, 0x16c0f429a256d}, + XY2D: FieldElement{0x69443903e9131, 0x16f4ac6f9dd36, + 0x2ea4912e29253, 0x2b4643e68d25d, 0x631eaf426bae7}}, + NielsPoint{YPlusX: FieldElement{0x175b9a3700de8, + 0x77c5f00aa48fb, 0x3917785ca0317, 0x5aa9b2c79399, 0x431f2c7f665f8}, + YMinusX: FieldElement{0x10410da66fe9f, 0x24d82dcb4d67d, + 0x3e6fe0e17752d, 0x4dade1ecbb08f, 0x5599648b1ea91}, + XY2D: FieldElement{0x26344858f7b19, 0x5f43d4a295ac0, + 0x242a75c52acd4, 0x5934480220d10, 0x7b04715f91253}}, + NielsPoint{YPlusX: FieldElement{0x6c280c4e6bac6, + 0x3ada3b361766e, 0x42fe5125c3b4f, 0x111d84d4aac22, 0x48d0acfa57cde}, + YMinusX: FieldElement{0x5bd28acf6ae43, 0x16fab8f56907d, + 0x7acb11218d5f2, 0x41fe02023b4db, 0x59b37bf5c2f65}, + XY2D: FieldElement{0x726e47dabe671, 0x2ec45e746f6c1, + 0x6580e53c74686, 0x5eda104673f74, 0x16234191336d3}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x19cd61ff38640, + 0x60c6c4b41ba9, 0x75cf70ca7366f, 0x118a8f16c011e, 0x4a25707a203b9}, + YMinusX: FieldElement{0x499def6267ff6, 0x76e858108773c, + 0x693cac5ddcb29, 0x311d00a9ff4, 0x2cdfdfecd5d05}, + XY2D: FieldElement{0x7668a53f6ed6a, 0x303ba2e142556, + 0x3880584c10909, 0x4fe20000a261d, 0x5721896d248e4}}, + NielsPoint{YPlusX: FieldElement{0x55091a1d0da4e, + 0x4f6bfc7c1050b, 0x64e4ecd2ea9be, 0x7eb1f28bbe70, 0x3c935afc4b03}, + YMinusX: FieldElement{0x65517fd181bae, 0x3e5772c76816d, + 0x19189640898a, 0x1ed2a84de7499, 0x578edd74f63c1}, + XY2D: FieldElement{0x276c6492b0c3d, 0x9bfc40bf932e, + 0x588e8f11f330b, 0x3d16e694dc26e, 0x3ec2ab590288c}}, + NielsPoint{YPlusX: FieldElement{0x13a09ae32d1cb, + 0x3e81eb85ab4e4, 0x7aaca43cae1f, 0x62f05d7526374, 0xe1bf66c6adba}, + YMinusX: FieldElement{0xd27be4d87bb9, 0x56c27235db434, + 0x72e6e0ea62d37, 0x5674cd06ee839, 0x2dd5c25a200fc}, + XY2D: FieldElement{0x3d5e9792c887e, 0x319724dabbc55, + 0x2b97c78680800, 0x7afdfdd34e6dd, 0x730548b35ae88}}, + NielsPoint{YPlusX: FieldElement{0x3094ba1d6e334, + 0x6e126a7e3300b, 0x89c0aefcfbc5, 0x2eea11f836583, 0x585a2277d8784}, + YMinusX: FieldElement{0x551a3cba8b8ee, 0x3b6422be2d886, + 0x630e1419689bc, 0x4653b07a7a955, 0x3043443b411db}, + XY2D: FieldElement{0x25f8233d48962, 0x6bd8f04aff431, + 0x4f907fd9a6312, 0x40fd3c737d29b, 0x7656278950ef9}}, + NielsPoint{YPlusX: FieldElement{0x73a3ea86cf9d, + 0x6e0e2abfb9c2e, 0x60e2a38ea33ee, 0x30b2429f3fe18, 0x28bbf484b613f}, + YMinusX: FieldElement{0x3cf59d51fc8c0, 0x7a0a0d6de4718, + 0x55c3a3e6fb74b, 0x353135f884fd5, 0x3f4160a8c1b84}, + XY2D: FieldElement{0x12f5c6f136c7c, 0xfedba237de4c, + 0x779bccebfab44, 0x3aea93f4d6909, 0x1e79cb358188f}}, + NielsPoint{YPlusX: FieldElement{0x153d8f5e08181, + 0x8533bbdb2efd, 0x1149796129431, 0x17a6e36168643, 0x478ab52d39d1f}, + YMinusX: FieldElement{0x436c3eef7e3f1, 0x7ffd3c21f0026, + 0x3e77bf20a2da9, 0x418bffc8472de, 0x65d7951b3a3b3}, + XY2D: FieldElement{0x6a4d39252d159, 0x790e35900ecd4, + 0x30725bf977786, 0x10a5c1635a053, 0x16d87a411a212}}, + NielsPoint{YPlusX: FieldElement{0x4d5e2d54e0583, + 0x2e5d7b33f5f74, 0x3a5de3f887ebf, 0x6ef24bd6139b7, 0x1f990b577a5a6}, + YMinusX: FieldElement{0x57e5a42066215, 0x1a18b44983677, + 0x3e652de1e6f8f, 0x6532be02ed8eb, 0x28f87c8165f38}, + XY2D: FieldElement{0x44ead1be8f7d6, 0x5759d4f31f466, + 0x378149f47943, 0x69f3be32b4f29, 0x45882fe1534d6}}, + NielsPoint{YPlusX: FieldElement{0x49929943c6fe4, + 0x4347072545b15, 0x3226bced7e7c5, 0x3a134ced89df, 0x7dcf843ce405f}, + YMinusX: FieldElement{0x1345d757983d6, 0x222f54234cccd, + 0x1784a3d8adbb4, 0x36ebeee8c2bcc, 0x688fe5b8f626f}, + XY2D: FieldElement{0xd6484a4732c0, 0x7b94ac6532d92, + 0x5771b8754850f, 0x48dd9df1461c8, 0x6739687e73271}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x5cc9dc80c1ac0, + 0x683671486d4cd, 0x76f5f1a5e8173, 0x6d5d3f5f9df4a, 0x7da0b8f68d7e7}, + YMinusX: FieldElement{0x2014385675a6, 0x6155fb53d1def, + 0x37ea32e89927c, 0x59a668f5a82e, 0x46115aba1d4dc}, + XY2D: FieldElement{0x71953c3b5da76, 0x6642233d37a81, + 0x2c9658076b1bd, 0x5a581e63010ff, 0x5a5f887e83674}}, + NielsPoint{YPlusX: FieldElement{0x628d3a0a643b9, + 0x1cd8640c93d2, 0xb7b0cad70f2c, 0x3864da98144be, 0x43e37ae2d5d1c}, + YMinusX: FieldElement{0x301cf70a13d11, 0x2a6a1ba1891ec, + 0x2f291fb3f3ae0, 0x21a7b814bea52, 0x3669b656e44d1}, + XY2D: FieldElement{0x63f06eda6e133, 0x233342758070f, + 0x98e0459cc075, 0x4df5ead6c7c1b, 0x6a21e6cd4fd5e}}, + NielsPoint{YPlusX: FieldElement{0x129126699b2e3, + 0xee11a2603de8, 0x60ac2f5c74c21, 0x59b192a196808, 0x45371b07001e8}, + YMinusX: FieldElement{0x6170a3046e65f, 0x5401a46a49e38, + 0x20add5561c4a8, 0x7abb4edde9e46, 0x586bf9f1a195f}, + XY2D: FieldElement{0x3088d5ef8790b, 0x38c2126fcb4db, + 0x685bae149e3c3, 0xbcd601a4e930, 0xeafb03790e52}}, + NielsPoint{YPlusX: FieldElement{0x805e0f75ae1d, + 0x464cc59860a28, 0x248e5b7b00bef, 0x5d99675ef8f75, 0x44ae3344c5435}, + YMinusX: FieldElement{0x555c13748042f, 0x4d041754232c0, + 0x521b430866907, 0x3308e40fb9c39, 0x309acc675a02c}, + XY2D: FieldElement{0x289b9bba543ee, 0x3ab592e28539e, + 0x64d82abcdd83a, 0x3c78ec172e327, 0x62d5221b7f946}}, + NielsPoint{YPlusX: FieldElement{0x5d4263af77a3c, + 0x23fdd2289aeb0, 0x7dc64f77eb9ec, 0x1bd28338402c, 0x14f29a5383922}, + YMinusX: FieldElement{0x4299c18d0936d, 0x5914183418a49, + 0x52a18c721aed5, 0x2b151ba82976d, 0x5c0efde4bc754}, + XY2D: FieldElement{0x17edc25b2d7f5, 0x37336a6081bee, + 0x7b5318887e5c3, 0x49f6d491a5be1, 0x5e72365c7bee0}}, + NielsPoint{YPlusX: FieldElement{0x339062f08b33e, + 0x4bbf3e657cfb2, 0x67af7f56e5967, 0x4dbd67f9ed68f, 0x70b20555cb734}, + YMinusX: FieldElement{0x3fc074571217f, 0x3a0d29b2b6aeb, + 0x6478ccdde59d, 0x55e4d051bddfa, 0x77f1104c47b4e}, + XY2D: FieldElement{0x113c555112c4c, 0x7535103f9b7ca, + 0x140ed1d9a2108, 0x2522333bc2af, 0xe34398f4a064}}, + NielsPoint{YPlusX: FieldElement{0x30b093e4b1928, + 0x1ce7e7ec80312, 0x4e575bdf78f84, 0x61f7a190bed39, 0x6f8aded6ca379}, + YMinusX: FieldElement{0x522d93ecebde8, 0x24f045e0f6cf, + 0x16db63426cfa1, 0x1b93a1fd30fd8, 0x5e5405368a362}, + XY2D: FieldElement{0x123dfdb7b29a, 0x4344356523c68, + 0x79a527921ee5f, 0x74bfccb3e817e, 0x780de72ec8d3d}}, + NielsPoint{YPlusX: FieldElement{0x7eaf300f42772, + 0x5455188354ce3, 0x4dcca4a3dcbac, 0x3d314d0bfebcb, 0x1defc6ad32b58}, + YMinusX: FieldElement{0x28545089ae7bc, 0x1e38fe9a0c15c, + 0x12046e0e2377b, 0x6721c560aa885, 0xeb28bf671928}, + XY2D: FieldElement{0x3be1aef5195a7, 0x6f22f62bdb5eb, + 0x39768b8523049, 0x43394c8fbfdbd, 0x467d201bf8dd2}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x6f4bd567ae7a9, + 0x65ac89317b783, 0x7d3b20fd8932, 0xf208326916, 0x2ef9c5a5ba384}, + YMinusX: FieldElement{0x6919a74ef4fad, 0x59ed4611452bf, + 0x691ec04ea09ef, 0x3cbcb2700e984, 0x71c43c4f5ba3c}, + XY2D: FieldElement{0x56df6fa9e74cd, 0x79c95e4cf56df, + 0x7be643bc609e2, 0x149c12ad9e878, 0x5a758ca390c5f}}, + NielsPoint{YPlusX: FieldElement{0x918b1d61dc94, + 0xd350260cd19c, 0x7a2ab4e37b4d9, 0x21fea735414d7, 0xa738027f639d}, + YMinusX: FieldElement{0x72710d9462495, 0x25aafaa007456, + 0x2d21f28eaa31b, 0x17671ea005fd0, 0x2dbae244b3eb7}, + XY2D: FieldElement{0x74a2f57ffe1cc, 0x1bc3073087301, + 0x7ec57f4019c34, 0x34e082e1fa524, 0x2698ca635126a}}, + NielsPoint{YPlusX: FieldElement{0x5702f5e3dd90e, + 0x31c9a4a70c5c7, 0x136a5aa78fc24, 0x1992f3b9f7b01, 0x3c004b0c4afa3}, + YMinusX: FieldElement{0x5318832b0ba78, 0x6f24b9ff17cec, + 0xa47f30e060c7, 0x58384540dc8d0, 0x1fb43dcc49cae}, + XY2D: FieldElement{0x146ac06f4b82b, 0x4b500d89e7355, + 0x3351e1c728a12, 0x10b9f69932fe3, 0x6b43fd01cd1fd}}, + NielsPoint{YPlusX: FieldElement{0x742583e760ef3, + 0x73dc1573216b8, 0x4ae48fdd7714a, 0x4f85f8a13e103, 0x73420b2d6ff0d}, + YMinusX: FieldElement{0x75d4b4697c544, 0x11be1fff7f8f4, + 0x119e16857f7e1, 0x38a14345cf5d5, 0x5a68d7105b52f}, + XY2D: FieldElement{0x4f6cb9e851e06, 0x278c4471895e5, + 0x7efcdce3d64e4, 0x64f6d455c4b4c, 0x3db5632fea34b}}, + NielsPoint{YPlusX: FieldElement{0x190b1829825d5, + 0xe7d3513225c9, 0x1c12be3b7abae, 0x58777781e9ca6, 0x59197ea495df2}, + YMinusX: FieldElement{0x6ee2bf75dd9d8, 0x6c72ceb34be8d, + 0x679c9cc345ec7, 0x7898df96898a4, 0x4321adf49d75}, + XY2D: FieldElement{0x16019e4e55aae, 0x74fc5f25d209c, + 0x4566a939ded0d, 0x66063e716e0b7, 0x45eafdc1f4d70}}, + NielsPoint{YPlusX: FieldElement{0x64624cfccb1ed, + 0x257ab8072b6c1, 0x120725676f0a, 0x4a018d04e8eee, 0x3f73ceea5d56d}, + YMinusX: FieldElement{0x401858045d72b, 0x459e5e0ca2d30, + 0x488b719308bea, 0x56f4a0d1b32b5, 0x5a5eebc80362d}, + XY2D: FieldElement{0x7bfd10a4e8dc6, 0x7c899366736f4, + 0x55ebbeaf95c01, 0x46db060903f8a, 0x2605889126621}}, + NielsPoint{YPlusX: FieldElement{0x18e3cc676e542, + 0x26079d995a990, 0x4a7c217908b2, 0x1dc7603e6655a, 0xdedfa10b2444}, + YMinusX: FieldElement{0x704a68360ff04, 0x3cecc3cde8b3e, + 0x21cd5470f64ff, 0x6abc18d953989, 0x54ad0c2e4e615}, + XY2D: FieldElement{0x367d5b82b522a, 0xd3f4b83d7dc7, + 0x3067f4cdbc58d, 0x20452da697937, 0x62ecb2baa77a9}}, + NielsPoint{YPlusX: FieldElement{0x72836afb62874, + 0xaf3c2094b240, 0xc285297f357a, 0x7cc2d5680d6e3, 0x61913d5075663}, + YMinusX: FieldElement{0x5795261152b3d, 0x7a1dbbafa3cbd, + 0x5ad31c52588d5, 0x45f3a4164685c, 0x2e59f919a966d}, + XY2D: FieldElement{0x62d361a3231da, 0x65284004e01b8, + 0x656533be91d60, 0x6ae016c00a89f, 0x3ddbc2a131c05}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x257a22796bb14, + 0x6f360fb443e75, 0x680e47220eaea, 0x2fcf2a5f10c18, 0x5ee7fb38d8320}, + YMinusX: FieldElement{0x40ff9ce5ec54b, 0x57185e261b35b, + 0x3e254540e70a9, 0x1b5814003e3f8, 0x78968314ac04b}, + XY2D: FieldElement{0x5fdcb41446a8e, 0x5286926ff2a71, + 0xf231e296b3f6, 0x684a357c84693, 0x61d0633c9bca0}}, + NielsPoint{YPlusX: FieldElement{0x328bcf8fc73df, + 0x3b4de06ff95b4, 0x30aa427ba11a5, 0x5ee31bfda6d9c, 0x5b23ac2df8067}, + YMinusX: FieldElement{0x44935ffdb2566, 0x12f016d176c6e, + 0x4fbb00f16f5ae, 0x3fab78d99402a, 0x6e965fd847aed}, + XY2D: FieldElement{0x2b953ee80527b, 0x55f5bcdb1b35a, + 0x43a0b3fa23c66, 0x76e07388b820a, 0x79b9bbb9dd95d}}, + NielsPoint{YPlusX: FieldElement{0x17dae8e9f7374, + 0x719f76102da33, 0x5117c2a80ca8b, 0x41a66b65d0936, 0x1ba811460accb}, + YMinusX: FieldElement{0x355406a3126c2, 0x50d1918727d76, + 0x6e5ea0b498e0e, 0xa3b6063214f2, 0x5065f158c9fd2}, + XY2D: FieldElement{0x169fb0c429954, 0x59aedd9ecee10, + 0x39916eb851802, 0x57917555cc538, 0x3981f39e58a4f}}, + NielsPoint{YPlusX: FieldElement{0x5dfa56de66fde, + 0x58809075908, 0x6d3d8cb854a94, 0x5b2f4e970b1e3, 0x30f4452edcbc1}, + YMinusX: FieldElement{0x38a7559230a93, 0x52c1cde8ba31f, + 0x2a4f2d4745a3d, 0x7e9d42d4a28a, 0x38dc083705acd}, + XY2D: FieldElement{0x52782c5759740, 0x53f3397d990ad, + 0x3a939c7e84d15, 0x234c4227e39e0, 0x632d9a1a593f2}}, + NielsPoint{YPlusX: FieldElement{0x1fd11ed0c84a7, + 0x21b3ed2757e1, 0x73e1de58fc1c6, 0x5d110c84616ab, 0x3a5a7df28af64}, + YMinusX: FieldElement{0x36b15b807cba6, 0x3f78a9e1afed7, + 0xa59c2c608f1f, 0x52bdd8ecb81b7, 0xb24f48847ed4}, + XY2D: FieldElement{0x2d4be511beac7, 0x6bda4d99e5b9b, + 0x17e6996914e01, 0x7b1f0ce7fcf80, 0x34fcf74475481}}, + NielsPoint{YPlusX: FieldElement{0x31dab78cfaa98, + 0x4e3216e5e54b7, 0x249823973b689, 0x2584984e48885, 0x119a3042fb37}, + YMinusX: FieldElement{0x7e04c789767ca, 0x1671b28cfb832, + 0x7e57ea2e1c537, 0x1fbaaef444141, 0x3d3bdc164dfa6}, + XY2D: FieldElement{0x2d89ce8c2177d, 0x6cd12ba182cf4, + 0x20a8ac19a7697, 0x539fab2cc72d9, 0x56c088f1ede20}}, + NielsPoint{YPlusX: FieldElement{0x35fac24f38f02, + 0x7d75c6197ab03, 0x33e4bc2a42fa7, 0x1c7cd10b48145, 0x38b7ea483590}, + YMinusX: FieldElement{0x53d1110a86e17, 0x6416eb65f466d, + 0x41ca6235fce20, 0x5c3fc8a99bb12, 0x9674c6b99108}, + XY2D: FieldElement{0x6f82199316ff8, 0x5d54f1a9f3e9, + 0x3bcc5d0bd274a, 0x5b284b8d2d5ad, 0x6e5e31025969e}}, + NielsPoint{YPlusX: FieldElement{0x4fb0e63066222, + 0x130f59747e660, 0x41868fecd41a, 0x3105e8c923bc6, 0x3058ad43d1838}, + YMinusX: FieldElement{0x462f587e593fb, 0x3d94ba7ce362d, + 0x330f9b52667b7, 0x5d45a48e0f00a, 0x8f5114789a8d}, + XY2D: FieldElement{0x40ffde57663d0, 0x71445d4c20647, + 0x2653e68170f7c, 0x64cdee3c55ed6, 0x26549fa4efe3d}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x68549af3f666e, + 0x9e2941d4bb68, 0x2e8311f5dff3c, 0x6429ef91ffbd2, 0x3a10dfe132ce3}, + YMinusX: FieldElement{0x55a461e6bf9d6, 0x78eeef4b02e83, + 0x1d34f648c16cf, 0x7fea2aba5132, 0x1926e1dc6401e}, + XY2D: FieldElement{0x74e8aea17cea0, 0xc743f83fbc0f, + 0x7cb03c4bf5455, 0x68a8ba9917e98, 0x1fa1d01d861e5}}, + NielsPoint{YPlusX: FieldElement{0x4ac00d1df94ab, + 0x3ba2101bd271b, 0x7578988b9c4af, 0xf2bf89f49f7e, 0x73fced18ee9a0}, + YMinusX: FieldElement{0x55947d599832, 0x346fe2aa41990, + 0x164c8079195b, 0x799ccfb7bba27, 0x773563bc6a75c}, + XY2D: FieldElement{0x1e90863139cb3, 0x4f8b407d9a0d6, + 0x58e24ca924f69, 0x7a246bbe76456, 0x1f426b701b864}}, + NielsPoint{YPlusX: FieldElement{0x635c891a12552, + 0x26aebd38ede2f, 0x66dc8faddae05, 0x21c7d41a03786, 0xb76bb1b3fa7e}, + YMinusX: FieldElement{0x1264c41911c01, 0x702f44584bdf9, + 0x43c511fc68ede, 0x482c3aed35f9, 0x4e1af5271d31b}, + XY2D: FieldElement{0xc1f97f92939b, 0x17a88956dc117, + 0x6ee005ef99dc7, 0x4aa9172b231cc, 0x7b6dd61eb772a}}, + NielsPoint{YPlusX: FieldElement{0xabf9ab01d2c7, + 0x3880287630ae6, 0x32eca045beddb, 0x57f43365f32d0, 0x53fa9b659bff6}, + YMinusX: FieldElement{0x5c1e850f33d92, 0x1ec119ab9f6f5, + 0x7f16f6de663e9, 0x7a7d6cb16dec6, 0x703e9bceaf1d2}, + XY2D: FieldElement{0x4c8e994885455, 0x4ccb5da9cad82, + 0x3596bc610e975, 0x7a80c0ddb9f5e, 0x398d93e5c4c61}}, + NielsPoint{YPlusX: FieldElement{0x77c60d2e7e3f2, + 0x4061051763870, 0x67bc4e0ecd2aa, 0x2bb941f1373b9, 0x699c9c9002c30}, + YMinusX: FieldElement{0x3d16733e248f3, 0xe2b7e14be389, + 0x42c0ddaf6784a, 0x589ea1fc67850, 0x53b09b5ddf191}, + XY2D: FieldElement{0x6a7235946f1cc, 0x6b99cbb2fbe60, + 0x6d3a5d6485c62, 0x4839466e923c0, 0x51caf30c6fcdd}}, + NielsPoint{YPlusX: FieldElement{0x2f99a18ac54c7, + 0x398a39661ee6f, 0x384331e40cde3, 0x4cd15c4de19a6, 0x12ae29c189f8e}, + YMinusX: FieldElement{0x3a7427674e00a, 0x6142f4f7e74c1, + 0x4cc93318c3a15, 0x6d51bac2b1ee7, 0x5504aa292383f}, + XY2D: FieldElement{0x6c0cb1f0d01cf, 0x187469ef5d533, + 0x27138883747bf, 0x2f52ae53a90e8, 0x5fd14fe958eba}}, + NielsPoint{YPlusX: FieldElement{0x2fe5ebf93cb8e, + 0x226da8acbe788, 0x10883a2fb7ea1, 0x94707842cf44, 0x7dd73f960725d}, + YMinusX: FieldElement{0x42ddf2845ab2c, 0x6214ffd3276bb, + 0xb8d181a5246, 0x268a6d579eb20, 0x93ff26e58647}, + XY2D: FieldElement{0x524fe68059829, 0x65b75e47cb621, + 0x15eb0a5d5cc19, 0x5209b3929d5a, 0x2f59bcbc86b47}}, + NielsPoint{YPlusX: FieldElement{0x1d560b691c301, + 0x7f5bafce3ce08, 0x4cd561614806c, 0x4588b6170b188, 0x2aa55e3d01082}, + YMinusX: FieldElement{0x47d429917135f, 0x3eacfa07af070, + 0x1deab46b46e44, 0x7a53f3ba46cdf, 0x5458b42e2e51a}, + XY2D: FieldElement{0x192e60c07444f, 0x5ae8843a21daa, + 0x6d721910b1538, 0x3321a95a6417e, 0x13e9004a8a768}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x600c9193b877f, + 0x21c1b8a0d7765, 0x379927fb38ea2, 0x70d7679dbe01b, 0x5f46040898de9}, + YMinusX: FieldElement{0x58845832fcedb, 0x135cd7f0c6e73, + 0x53ffbdfe8e35b, 0x22f195e06e55b, 0x73937e8814bce}, + XY2D: FieldElement{0x37116297bf48d, 0x45a9e0d069720, + 0x25af71aa744ec, 0x41af0cb8aaba3, 0x2cf8a4e891d5e}}, + NielsPoint{YPlusX: FieldElement{0x5487e17d06ba2, + 0x3872a032d6596, 0x65e28c09348e0, 0x27b6bb2ce40c2, 0x7a6f7f2891d6a}, + YMinusX: FieldElement{0x3fd8707110f67, 0x26f8716a92db2, + 0x1cdaa1b753027, 0x504be58b52661, 0x2049bd6e58252}, + XY2D: FieldElement{0x1fd8d6a9aef49, 0x7cb67b7216fa1, + 0x67aff53c3b982, 0x20ea610da9628, 0x6011aadfc5459}}, + NielsPoint{YPlusX: FieldElement{0x6d0c802cbf890, + 0x141bfed554c7b, 0x6dbb667ef4263, 0x58f3126857edc, 0x69ce18b779340}, + YMinusX: FieldElement{0x7926dcf95f83c, 0x42e25120e2bec, + 0x63de96df1fa15, 0x4f06b50f3f9cc, 0x6fc5cc1b0b62f}, + XY2D: FieldElement{0x75528b29879cb, 0x79a8fd2125a3d, + 0x27c8d4b746ab8, 0xf8893f02210c, 0x15596b3ae5710}}, + NielsPoint{YPlusX: FieldElement{0x731167e5124ca, + 0x17b38e8bbe13f, 0x3d55b942f9056, 0x9c1495be913f, 0x3aa4e241afb6d}, + YMinusX: FieldElement{0x739d23f9179a2, 0x632fadbb9e8c4, + 0x7c8522bfe0c48, 0x6ed0983ef5aa9, 0xd2237687b5f4}, + XY2D: FieldElement{0x138bf2a3305f5, 0x1f45d24d86598, + 0x5274bad2160fe, 0x1b6041d58d12a, 0x32fcaa6e4687a}}, + NielsPoint{YPlusX: FieldElement{0x7a4732787ccdf, + 0x11e427c7f0640, 0x3659385f8c64, 0x5f4ead9766bfb, 0x746f6336c2600}, + YMinusX: FieldElement{0x56e8dc57d9af5, 0x5b3be17be4f78, + 0x3bf928cf82f4b, 0x52e55600a6f11, 0x4627e9cefebd6}, + XY2D: FieldElement{0x2f345ab6c971c, 0x653286e63e7e9, + 0x51061b78a23ad, 0x14999acb54501, 0x7b4917007ed66}}, + NielsPoint{YPlusX: FieldElement{0x41b28dd53a2dd, + 0x37be85f87ea86, 0x74be3d2a85e41, 0x1be87fac96ca6, 0x1d03620fe08cd}, + YMinusX: FieldElement{0x5fb5cab84b064, 0x2513e778285b0, + 0x457383125e043, 0x6bda3b56e223d, 0x122ba376f844f}, + XY2D: FieldElement{0x232cda2b4e554, 0x422ba30ff840, + 0x751e7667b43f5, 0x6261755da5f3e, 0x2c70bf52b68e}}, + NielsPoint{YPlusX: FieldElement{0x532bf458d72e1, + 0x40f96e796b59c, 0x22ef79d6f9da3, 0x501ab67beca77, 0x6b0697e3feb43}, + YMinusX: FieldElement{0x7ec4b5d0b2fbb, 0x200e910595450, + 0x742057105715e, 0x2f07022530f60, 0x26334f0a409ef}, + XY2D: FieldElement{0xf04adf62a3c0, 0x5e0edb48bb6d9, + 0x7c34aa4fbc003, 0x7d74e4e5cac24, 0x1cc37f43441b2}}, + NielsPoint{YPlusX: FieldElement{0x656f1c9ceaeb9, + 0x7031cacad5aec, 0x1308cd0716c57, 0x41c1373941942, 0x3a346f772f196}, + YMinusX: FieldElement{0x7565a5cc7324f, 0x1ca0d5244a11, + 0x116b067418713, 0xa57d8c55edae, 0x6c6809c103803}, + XY2D: FieldElement{0x55112e2da6ac8, 0x6363d0a3dba5a, + 0x319c98ba6f40c, 0x2e84b03a36ec7, 0x5911b9f6ef7c}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x1acf3512eeaef, + 0x2639839692a69, 0x669a234830507, 0x68b920c0603d4, 0x555ef9d1c64b2}, + YMinusX: FieldElement{0x39983f5df0ebb, 0x1ea2589959826, + 0x6ce638703cdd6, 0x6311678898505, 0x6b3cecf9aa270}, + XY2D: FieldElement{0x770ba3b73bd08, 0x11475f7e186d4, + 0x251bc9892bbc, 0x24eab9bffcc5a, 0x675f4de133817}}, + NielsPoint{YPlusX: FieldElement{0x7f6d93bdab31d, + 0x1f3aca5bfd425, 0x2fa521c1c9760, 0x62180ce27f9cd, 0x60f450b882cd3}, + YMinusX: FieldElement{0x452036b1782fc, 0x2d95b07681c5, + 0x5901cf99205b2, 0x290686e5eecb4, 0x13d99df70164c}, + XY2D: FieldElement{0x35ec321e5c0ca, 0x13ae337f44029, + 0x4008e813f2da7, 0x640272f8e0c3a, 0x1c06de9e55eda}}, + NielsPoint{YPlusX: FieldElement{0x52b40ff6d69aa, + 0x31b8809377ffa, 0x536625cd14c2c, 0x516af252e17d1, 0x78096f8e7d32b}, + YMinusX: FieldElement{0x77ad6a33ec4e2, 0x717c5dc11d321, + 0x4a114559823e4, 0x306ce50a1e2b1, 0x4cf38a1fec2db}, + XY2D: FieldElement{0x2aa650dfa5ce7, 0x54916a8f19415, + 0xdc96fe71278, 0x55f2784e63eb8, 0x373cad3a26091}}, + NielsPoint{YPlusX: FieldElement{0x6a8fb89ddbbad, + 0x78c35d5d97e37, 0x66e3674ef2cb2, 0x34347ac53dd8f, 0x21547eda5112a}, + YMinusX: FieldElement{0x4634d82c9f57c, 0x4249268a6d652, + 0x6336d687f2ff7, 0x4fe4f4e26d9a0, 0x40f3d945441}, + XY2D: FieldElement{0x5e939fd5986d3, 0x12a2147019bdf, + 0x4c466e7d09cb2, 0x6fa5b95d203dd, 0x63550a334a254}}, + NielsPoint{YPlusX: FieldElement{0x2584572547b49, + 0x75c58811c1377, 0x4d3c637cc171b, 0x33d30747d34e3, 0x39a92bafaa7d7}, + YMinusX: FieldElement{0x7d6edb569cf37, 0x60194a5dc2ca0, + 0x5af59745e10a6, 0x7a8f53e004875, 0x3eea62c7daf78}, + XY2D: FieldElement{0x4c713e693274e, 0x6ed1b7a6eb3a4, + 0x62ace697d8e15, 0x266b8292ab075, 0x68436a0665c9c}}, + NielsPoint{YPlusX: FieldElement{0x6d317e820107c, + 0x90815d2ca3ca, 0x3ff1eb1499a1, 0x23960f050e319, 0x5373669c91611}, + YMinusX: FieldElement{0x235e8202f3f27, 0x44c9f2eb61780, + 0x630905b1d7003, 0x4fcc8d274ead1, 0x17b6e7f68ab78}, + XY2D: FieldElement{0x14ab9a0e5257, 0x9939567f8ba5, + 0x4b47b2a423c82, 0x688d7e57ac42d, 0x1cb4b5a678f87}}, + NielsPoint{YPlusX: FieldElement{0x4aa62a2a007e7, + 0x61e0e38f62d6e, 0x2f888fcc4782, 0x7562b83f21c00, 0x2dc0fd2d82ef6}, + YMinusX: FieldElement{0x4c06b394afc6c, 0x4931b4bf636cc, + 0x72b60d0322378, 0x25127c6818b25, 0x330bca78de743}, + XY2D: FieldElement{0x6ff841119744e, 0x2c560e8e49305, + 0x7254fefe5a57a, 0x67ae2c560a7df, 0x3c31be1b369f1}}, + NielsPoint{YPlusX: FieldElement{0xbc93f9cb4272, + 0x3f8f9db73182d, 0x2b235eabae1c4, 0x2ddbf8729551a, 0x41cec1097e7d5}, + YMinusX: FieldElement{0x4864d08948aee, 0x5d237438df61e, + 0x2b285601f7067, 0x25dbcbae6d753, 0x330b61134262d}, + XY2D: FieldElement{0x619d7a26d808a, 0x3c3b3c2adbef2, + 0x6877c9eec7f52, 0x3beb9ebe1b66d, 0x26b44cd91f287}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x7f29362730383, + 0x7fd7951459c36, 0x7504c512d49e7, 0x87ed7e3bc55f, 0x7deb10149c726}, + YMinusX: FieldElement{0x48478f387475, 0x69397d9678a3e, + 0x67c8156c976f3, 0x2eb4d5589226c, 0x2c709e6c1c10a}, + XY2D: FieldElement{0x2af6a8766ee7a, 0x8aaa79a1d96c, + 0x42f92d59b2fb0, 0x1752c40009c07, 0x8e68e9ff62ce}}, + NielsPoint{YPlusX: FieldElement{0x509d50ab8f2f9, + 0x1b8ab247be5e5, 0x5d9b2e6b2e486, 0x4faa5479a1339, 0x4cb13bd738f71}, + YMinusX: FieldElement{0x5500a4bc130ad, 0x127a17a938695, + 0x2a26fa34e36d, 0x584d12e1ecc28, 0x2f1f3f87eeba3}, + XY2D: FieldElement{0x48c75e515b64a, 0x75b6952071ef0, + 0x5d46d42965406, 0x7746106989f9f, 0x19a1e353c0ae2}}, + NielsPoint{YPlusX: FieldElement{0x172cdd596bdbd, + 0x731ddf881684, 0x10426d64f8115, 0x71a4fd8a9a3da, 0x736bd3990266a}, + YMinusX: FieldElement{0x47560bafa05c3, 0x418dcabcc2fa3, + 0x35991cecf8682, 0x24371a94b8c60, 0x41546b11c20c3}, + XY2D: FieldElement{0x32d509334b3b4, 0x16c102cae70aa, + 0x1720dd51bf445, 0x5ae662faf9821, 0x412295a2b87fa}}, + NielsPoint{YPlusX: FieldElement{0x55261e293eac6, + 0x6426759b65cc, 0x40265ae116a48, 0x6c02304bae5bc, 0x760bb8d195ad}, + YMinusX: FieldElement{0x19b88f57ed6e9, 0x4cdbf1904a339, + 0x42b49cd4e4f2c, 0x71a2e771909d9, 0x14e153ebb52d2}, + XY2D: FieldElement{0x61a17cde6818a, 0x53dad34108827, + 0x32b32c55c55b6, 0x2f9165f9347a3, 0x6b34be9bc33ac}}, + NielsPoint{YPlusX: FieldElement{0x469656571f2d3, + 0xaa61ce6f423f, 0x3f940d71b27a1, 0x185f19d73d16a, 0x1b9c7b62e6dd}, + YMinusX: FieldElement{0x72f643a78c0b2, 0x3de45c04f9e7b, + 0x706d68d30fa5c, 0x696f63e8e2f24, 0x2012c18f0922d}, + XY2D: FieldElement{0x355e55ac89d29, 0x3e8b414ec7101, + 0x39db07c520c90, 0x6f41e9b77efe1, 0x8af5b784e4ba}}, + NielsPoint{YPlusX: FieldElement{0x314d289cc2c4b, + 0x23450e2f1bc4e, 0xcd93392f92f4, 0x1370c6a946b7d, 0x6423c1d5afd98}, + YMinusX: FieldElement{0x499dc881f2533, 0x34ef26476c506, + 0x4d107d2741497, 0x346c4bd6efdb3, 0x32b79d71163a1}, + XY2D: FieldElement{0x5f8d9edfcb36a, 0x1e6e8dcbf3990, + 0x7974f348af30a, 0x6e6724ef19c7c, 0x480a5efbc13e2}}, + NielsPoint{YPlusX: FieldElement{0x14ce442ce221f, + 0x18980a72516cc, 0x72f80db86677, 0x703331fda526e, 0x24b31d47691c8}, + YMinusX: FieldElement{0x1e70b01622071, 0x1f163b5f8a16a, + 0x56aaf341ad417, 0x7989635d830f7, 0x47aa27600cb7b}, + XY2D: FieldElement{0x41eedc015f8c3, 0x7cf8d27ef854a, + 0x289e3584693f9, 0x4a7857b309a7, 0x545b585d14dda}}, + NielsPoint{YPlusX: FieldElement{0x4e4d0e3b321e1, + 0x7451fe3d2ac40, 0x666f678eea98d, 0x38858667fead, 0x4d22dc3e64c8d}, + YMinusX: FieldElement{0x7275ea0d43a0f, 0x681137dd7ccf7, + 0x1e79cbab79a38, 0x22a214489a66a, 0xf62f9c332ba5}, + XY2D: FieldElement{0x46589d63b5f39, 0x7eaf979ec3f96, + 0x4ebe81572b9a8, 0x21b7f5d61694a, 0x1c0fa01a36371}}}, + [8]NielsPoint{NielsPoint{YPlusX: FieldElement{0x2b0e8c936a50, + 0x6b83b58b6cd21, 0x37ed8d3e72680, 0xa037db9f2a62, 0x4005419b1d2bc}, + YMinusX: FieldElement{0x604b622943dff, 0x1c899f6741a58, + 0x60219e2f232fb, 0x35fae92a7f9cb, 0xfa3614f3b1ca}, + XY2D: FieldElement{0x3febdb9be82f0, 0x5e74895921400, + 0x553ea38822706, 0x5a17c24cfc88c, 0x1fba218aef40a}}, + NielsPoint{YPlusX: FieldElement{0x657043e7b0194, + 0x5c11b55efe9e7, 0x7737bc6a074fb, 0xeae41ce355cc, 0x6c535d13ff776}, + YMinusX: FieldElement{0x49448fac8f53e, 0x34f74c6e8356a, + 0xad780607dba2, 0x7213a7eb63eb6, 0x392e3acaa8c86}, + XY2D: FieldElement{0x534e93e8a35af, 0x8b10fd02c997, + 0x26ac2acb81e05, 0x9d8c98ce3b79, 0x25e17fe4d50ac}}, + NielsPoint{YPlusX: FieldElement{0x77ff576f121a7, + 0x4e5f9b0fc722b, 0x46f949b0d28c8, 0x4cde65d17ef26, 0x6bba828f89698}, + YMinusX: FieldElement{0x9bd71e04f676, 0x25ac841f2a145, + 0x1a47eac823871, 0x1a8a8c36c581a, 0x255751442a9fb}, + XY2D: FieldElement{0x1bc6690fe3901, 0x314132f5abc5a, + 0x611835132d528, 0x5f24b8eb48a57, 0x559d504f7f6b7}}, + NielsPoint{YPlusX: FieldElement{0x91e7f6d266fd, + 0x36060ef037389, 0x18788ec1d1286, 0x287441c478eb0, 0x123ea6a3354bd}, + YMinusX: FieldElement{0x38378b3eb54d5, 0x4d4aaa78f94ee, + 0x4a002e875a74d, 0x10b851367b17c, 0x1ab12d5807e3}, + XY2D: FieldElement{0x5189041e32d96, 0x5b062b090231, + 0xc91766e7b78f, 0xaa0f55a138ec, 0x4a3961e2c918a}}, + NielsPoint{YPlusX: FieldElement{0x7d644f3233f1e, + 0x1c69f9e02c064, 0x36ae5e5266898, 0x8fc1dad38b79, 0x68aceead9bd41}, + YMinusX: FieldElement{0x43be0f8e6bba0, 0x68fdffc614e3b, + 0x4e91dab5b3be0, 0x3b1d4c9212ff0, 0x2cd6bce3fb1db}, + XY2D: FieldElement{0x4c90ef3d7c210, 0x496f5a0818716, + 0x79cf88cc239b8, 0x2cb9c306cf8db, 0x595760d5b508f}}, + NielsPoint{YPlusX: FieldElement{0x2cbebfd022790, + 0xb8822aec1105, 0x4d1cfd226bccc, 0x515b2fa4971be, 0x2cb2c5df54515}, + YMinusX: FieldElement{0x1bfe104aa6397, 0x11494ff996c25, + 0x64251623e5800, 0xd49fc5e044be, 0x709fa43edcb29}, + XY2D: FieldElement{0x25d8c63fd2aca, 0x4c5cd29dffd61, + 0x32ec0eb48af05, 0x18f9391f9b77c, 0x70f029ecf0c81}}, + NielsPoint{YPlusX: FieldElement{0x2afaa5e10b0b9, + 0x61de08355254d, 0xeb587de3c28d, 0x4f0bb9f7dbbd5, 0x44eca5a2a74bd}, + YMinusX: FieldElement{0x307b32eed3e33, 0x6748ab03ce8c2, + 0x57c0d9ab810bc, 0x42c64a224e98c, 0xb7d5d8a6c314}, + XY2D: FieldElement{0x448327b95d543, 0x146681e3a4ba, + 0x38714adc34e0c, 0x4f26f0e298e30, 0x272224512c7de}}, + NielsPoint{YPlusX: FieldElement{0x3bb8a42a975fc, + 0x6f2d5b46b17ef, 0x7b6a9223170e5, 0x53713fe3b7e6, 0x19735fd7f6bc2}, + YMinusX: FieldElement{0x492af49c5342e, 0x2365cdf5a0357, + 0x32138a7ffbb60, 0x2a1f7d14646fe, 0x11b5df18a44cc}, + XY2D: FieldElement{0x390d042c84266, 0x1efe32a8fdc75, + 0x6925ee7ae1238, 0x4af9281d0e832, 0xfef911191df8}}}} diff --git a/vendor/github.com/bwesterb/go-ristretto/edwards25519/vartime.go b/vendor/github.com/bwesterb/go-ristretto/edwards25519/vartime.go new file mode 100644 index 0000000000..2fc63d955c --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/edwards25519/vartime.go @@ -0,0 +1,117 @@ +package edwards25519 + +func load8u(in []byte) uint64 { + var r uint64 + r = uint64(in[0]) + r |= uint64(in[1]) << 8 + r |= uint64(in[2]) << 16 + r |= uint64(in[3]) << 24 + r |= uint64(in[4]) << 32 + r |= uint64(in[5]) << 40 + r |= uint64(in[6]) << 48 + r |= uint64(in[7]) << 56 + return r +} + +// Computes the w=5 w-NAF of s and store it into naf. +// naf is assumed to be zero-initialized and the highest three bits of s +// have to be cleared. +func computeScalar5NAF(s *[32]byte, naf *[256]int8) { + var x [5]uint64 + for i := 0; i < 4; i++ { + x[i] = load8u(s[i*8 : (i+1)*8]) + } + pos := uint16(0) + carry := uint64(0) + for pos < 256 { + idx := pos / 64 + bit_idx := pos % 64 + var bit_buf uint64 + if bit_idx < 59 { + bit_buf = x[idx] >> bit_idx + } else { + bit_buf = (x[idx] >> bit_idx) | (x[1+idx] << (64 - bit_idx)) + } + window := carry + (bit_buf & 31) + if window&1 == 0 { + pos += 1 + continue + } + + if window < 16 { + carry = 0 + naf[pos] = int8(window) + } else { + carry = 1 + naf[pos] = int8(window) - int8(32) + } + + pos += 5 + } +} + +func (p *ExtendedPoint) VarTimeScalarMult(q *ExtendedPoint, s *[32]byte) *ExtendedPoint { + var lut [8]ExtendedPoint + + // Precomputations + var dblQ ExtendedPoint + dblQ.Double(q) + lut[0].Set(q) + for i := 1; i < 8; i++ { + lut[i].Add(&lut[i-1], &dblQ) + } + + // Compute non-adjacent form of s + var naf [256]int8 + computeScalar5NAF(s, &naf) + + // Skip the trailing zeroes + i := 255 + for ; i >= 0; i-- { + if naf[i] != 0 { + break + } + } + + // Corner-case: s is zero. + p.SetZero() + if i == -1 { + return p + } + + var pp ProjectivePoint + var cp CompletedPoint + for { + if naf[i] > 0 { + cp.AddExtended(p, &lut[(naf[i]+1)/2-1]) + } else { + cp.SubExtended(p, &lut[(1-naf[i])/2-1]) + } + + if i == 0 { + p.SetCompleted(&cp) + break + } + + i -= 1 + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + + // Find next non-zero digit + for { + if i == 0 || naf[i] != 0 { + break + } + i -= 1 + pp.SetCompleted(&cp) + cp.DoubleProjective(&pp) + } + p.SetCompleted(&cp) + + if naf[i] == 0 { + break + } + } + + return p +} diff --git a/vendor/github.com/bwesterb/go-ristretto/ristretto.go b/vendor/github.com/bwesterb/go-ristretto/ristretto.go new file mode 100644 index 0000000000..d775e9e5b1 --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/ristretto.go @@ -0,0 +1,405 @@ +// Pure Go implementation of the Ristretto prime-order group built from +// the Edwards curve Edwards25519. +// +// Many cryptographic schemes need a group of prime order. Popular and +// efficient elliptic curves like (Edwards25519 of `ed25519` fame) are +// rarely of prime order. There is, however, a convenient method +// to construct a prime order group from such curves, using a method +// called Ristretto proposed by Mike Hamburg. +// +// This package implements the Ristretto group constructed from Edwards25519. +// The Point type represents a group element. The API mimics that of the +// math/big package. For instance, to set c to a+b, one writes +// +// var c ristretto.Point +// c.Add(&a, &b) // sets c to a + b +// +// Warning: contrary to math.Big's interface, an uninitialized Point is not +// the same thing as the zero (neutral element) of the group: +// +// var c ristretto.Point // c is uninitialized now --- not zero! +// c.SetZero() // c is zero now; ready to use! +// +// Most methods return the receiver, so that function can be chained: +// +// s.Add(&a, &b).Add(&s, &c) // sets s to a + b + c +// +// The order of the Ristretto group is l = +// 2^252 + 27742317777372353535851937790883648493 = +// 7237005577332262213973186563042994240857116359379907606001950938285454250989. +// The Scalar type implement the numbers modulo l and also has an API similar +// to math/big. +package ristretto + +import ( + "crypto/rand" + "crypto/sha256" + "crypto/sha512" + "crypto/subtle" + "encoding/base64" + "encoding/hex" + "errors" + "fmt" + + "github.com/bwesterb/go-ristretto/edwards25519" +) + +// Represents an element of the Ristretto group over Edwards25519. +// +// Warning: an uninitialized Point is not the same thing as a zero. Use +// the SetZero() method to set an (uninitialized) Point to zero. +type Point edwards25519.ExtendedPoint + +// A table to speed up scalar multiplication of a fixed point +type ScalarMultTable edwards25519.ScalarMultTable + +// Sets p to zero (the neutral element). Returns p. +func (p *Point) SetZero() *Point { + p.e().SetZero() + return p +} + +// Sets p to the Edwards25519 basepoint. Returns p +func (p *Point) SetBase() *Point { + p.e().SetBase() + return p +} + +// Sets p to q. Returns p +func (p *Point) Set(q *Point) *Point { + p.e().Set(q.e()) + return p +} + +// Sets p to q + r. Returns p. +func (p *Point) Add(q, r *Point) *Point { + p.e().Add(q.e(), r.e()) + return p +} + +// Sets p to q + q. Returns p. +func (p *Point) Double(q *Point) *Point { + p.e().Double(q.e()) + return p +} + +// Sets p to q - r. Returns p. +func (p *Point) Sub(q, r *Point) *Point { + p.e().Sub(q.e(), r.e()) + return p +} + +// Sets p to -q. Returns p. +func (p *Point) Neg(q *Point) *Point { + p.e().Neg(q.e()) + return p +} + +// Packs p into the given buffer. Returns p. +func (p *Point) BytesInto(buf *[32]byte) *Point { + p.e().RistrettoInto(buf) + return p +} + +// Returns a packed version of p. +func (p *Point) Bytes() []byte { + return p.e().Ristretto() +} + +// Sets p to the point encoded in buf using Bytes(). +// Not every input encodes a point. Returns whether the buffer encoded a point. +func (p *Point) SetBytes(buf *[32]byte) bool { + return p.e().SetRistretto(buf) +} + +// Sets p to the point corresponding to buf using the Elligator2 encoding. +// +// In contrast to SetBytes() (1) Every input buffer will decode to a point +// and (2) SetElligator() is not injective: for every point there are +// approximately four buffers that will encode to it. +func (p *Point) SetElligator(buf *[32]byte) *Point { + var fe edwards25519.FieldElement + var cp edwards25519.CompletedPoint + fe.SetBytes(buf) + cp.SetRistrettoElligator2(&fe) + p.e().SetCompleted(&cp) + return p +} + +// Sets p to s * q, where q is the point for which the table t was +// computed. Returns p. +func (p *Point) ScalarMultTable(t *ScalarMultTable, s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + t.t().ScalarMult(p.e(), &buf) + return p +} + +// Sets p to s * q, where q is the point for which the table t was +// computed. Returns p. +// +// Warning: this method uses a non-constant time inmplementation and thus leaks +// information about s. Use this function only if s is public knowledge. +func (p *Point) PublicScalarMultTable(t *ScalarMultTable, s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + t.t().VarTimeScalarMult(p.e(), &buf) + return p +} + +// Sets p to s * q. Returns p. +func (p *Point) ScalarMult(q *Point, s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + p.e().ScalarMult(q.e(), &buf) + return p +} + +// Sets p to s * q assuming s is *not* secret. Returns p. +// +// Warning: this method uses a non-constant time inmplementation and thus leaks +// information about s. Use this function only if s is public knowledge. +func (p *Point) PublicScalarMult(q *Point, s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + p.e().VarTimeScalarMult(q.e(), &buf) + return p +} + +// Sets p to s * B, where B is the edwards25519 basepoint. Returns p. +// +// Warning: this method uses a non-constant time inmplementation and thus leaks +// information about s. Use this function only if s is public knowledge. +func (p *Point) PublicScalarMultBase(s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + edwards25519.BaseScalarMultTable.VarTimeScalarMult(p.e(), &buf) + return p +} + +// Sets p to s * B, where B is the edwards25519 basepoint. Returns p. +func (p *Point) ScalarMultBase(s *Scalar) *Point { + var buf [32]byte + s.BytesInto(&buf) + edwards25519.BaseScalarMultTable.ScalarMult(p.e(), &buf) + return p +} + +// Sets p to a random point. Returns p. +func (p *Point) Rand() *Point { + var buf [32]byte + rand.Read(buf[:]) + return p.SetElligator(&buf) +} + +// Sets p to the point derived from the buffer using SHA512 and Elligator2. +// Returns p. +// +// NOTE curve25519-dalek uses a different (more conservative) method to derive +// a point from raw data with a hash. This is implemented in +// Point.DeriveDalek(). +func (p *Point) Derive(buf []byte) *Point { + var ptBuf [32]byte + h := sha512.Sum512(buf) + copy(ptBuf[:], h[:32]) + return p.SetElligator(&ptBuf) +} + +// Encode 16 bytes into a point using the Lizard method. +// +// Use Lizard() or LizardInto() to decode the bytes from a Point. +// +// Notes on usage: +// +// - If you want to create a Point from random data, you should rather +// create a random Point with Point.Rand() and then use (a hash of) +// Point.Bytes() as the random data. +// - If you want to derive a Point from data, but you do not care about +// decoding the data back from the point, you should use +// the Point.Derive() method instead. +// - There are some (and with high probability at most 80) inputs to +// SetLizard() which cannot be decoded. The chance that you hit such +// an input is around 1 in 2^122. +// +// In Lizard there are 256 - 128 - 3 = 125 check bits to pick out the +// right preimage among at most eight. Conservatively assuming there are +// seven other preimages, the chance that one of them passes the check as +// well is given by: +// +// 1 - (1 - 2^-125)^7 = 7*2^-125 + 21*2^-250 - ... +// =~ 2^(-125 - 2log(7)) +// = 2^-122.192... +// +// Presuming a random hash function, the number of "bad" inputs is binomially +// distributed with n=2^128 and p=2^-122.192... For such large n, the Poisson +// distribution with lambda=n*p=56 is a very good approximation. In fact: +// the cumulative distribution function (CDF) of the Poission distribution +// is larger than that of the binomial distribution for k > lambda.[1] The value +// of the former on k=80 is larger than 0.999 and so with a probability of 99.9%, +// there are fewer than 80 bad inputs. +// +// [1] See "Some Inequalities Among Binomial and Poisson Probabilities" +// by Anderson and Samuels in Proc. Fifth Berkeley Symp. on +// Math. Statist. and Prob., Vol. 1 (Univ. of Calif. Press, 1967). +func (p *Point) SetLizard(data *[16]byte) *Point { + var fe edwards25519.FieldElement + var cp edwards25519.CompletedPoint + buf := sha256.Sum256(data[:]) + copy(buf[8:], data[:]) + buf[0] &= 254 // clear lowest bit to make the FieldElement positive + buf[31] &= 63 // clear highest two bits to ensure below 2^255-19. + fe.SetBytes(&buf) + cp.SetRistrettoElligator2(&fe) + p.e().SetCompleted(&cp) + return p +} + +// Decodes 16 bytes encoded into this point using SetLizard(). +// +// Returns nil if this point does not contain data encoded using Lizard. +// +// See SetLizard() for notes on usage. +func (p *Point) Lizard() []byte { + var ret [16]byte + if p.LizardInto(&ret) != nil { + return nil + } + return ret[:] +} + +// Decodes 16 bytes into the given buffer encoded into this point +// using SetLizard(). +// +// See SetLizard() for notes on usage. +func (p *Point) LizardInto(buf *[16]byte) error { + var fes [8]edwards25519.FieldElement + var buf2 [32]byte + var nFound uint8 + + mask := p.e().RistrettoElligator2Inverse(&fes) + + for j := 0; j < 8; j++ { + ok := (mask >> uint(j)) & 1 + fes[j].BytesInto(&buf2) + h := sha256.Sum256(buf2[8:24]) + copy(h[8:], buf2[8:24]) + h[0] &= 254 + h[31] &= 63 + ok &= uint8(subtle.ConstantTimeCompare(h[:], buf2[:])) + subtle.ConstantTimeCopy(int(ok), buf[:], buf2[8:24]) + nFound += ok + } + if nFound == 1 { + return nil + } + if nFound == 0 { + return errors.New("No Lizard preimage") + } + return errors.New("Multiple Lizard preimages") +} + +// Returns 1 if p == q and 0 otherwise. +func (p *Point) EqualsI(q *Point) int32 { + return p.e().RistrettoEqualsI(q.e()) +} + +// Returns whether p == q +func (p *Point) Equals(q *Point) bool { + return p.EqualsI(q) == 1 +} + +// Sets p to the point derived from the buffer using SHA512 and Elligator2 +// in the fashion of curve25519-dalek. +// +// NOTE See also Derive(), which is a different method which is twice as fast, +// but which might not be as secure as this method. +func (p *Point) DeriveDalek(data []byte) *Point { + hash := sha512.Sum512(data) + var p2 Point + var buf [32]byte + copy(buf[:], hash[:32]) + p.SetElligator(&buf) + copy(buf[:], hash[32:]) + p2.SetElligator(&buf) + p.Add(p, &p2) + return p +} + +// Implements encoding/BinaryUnmarshaler. Use SetBytes, if convenient, instead. +func (p *Point) UnmarshalBinary(data []byte) error { + if len(data) != 32 { + return fmt.Errorf("ristretto.Point should be 32 bytes; not %d", len(data)) + } + var buf [32]byte + copy(buf[:], data) + if !p.SetBytes(&buf) { + return errors.New("Buffer does not encode a ristretto.Point") + } + return nil +} + +// Implements encoding/BinaryMarshaler. Use BytesInto, if convenient, instead. +func (p *Point) MarshalBinary() ([]byte, error) { + var buf [32]byte + p.BytesInto(&buf) + return buf[:], nil +} + +func (p *Point) MarshalText() ([]byte, error) { + enc := base64.RawURLEncoding + var buf [32]byte + p.BytesInto(&buf) + ret := make([]byte, enc.EncodedLen(32)) + enc.Encode(ret, buf[:]) + return ret, nil +} + +func textToBuf(dst, src []byte) error { + var n int + var err error + if len(src) == 64 { + n, err = hex.Decode(dst, src) + if n == 32 && err == nil { + return nil + } + } + enc := base64.RawURLEncoding + n, err = enc.Decode(dst, src) + if err != nil { + return err + } + if n != 32 { + return fmt.Errorf("ristretto.Point should be 32 bytes; not %d", n) + } + return nil +} + +func (p *Point) UnmarshalText(txt []byte) error { + var buf [32]byte + err := textToBuf(buf[:], txt) + if err != nil { + return err + } + if !p.SetBytes(&buf) { + return errors.New("Buffer does not encode a ristretto.Point") + } + return nil +} + +func (p Point) String() string { + text, _ := p.MarshalText() + return string(text) +} + +func (p *Point) e() *edwards25519.ExtendedPoint { + return (*edwards25519.ExtendedPoint)(p) +} + +func (t *ScalarMultTable) t() *edwards25519.ScalarMultTable { + return (*edwards25519.ScalarMultTable)(t) +} + +// Fills the table for point p. +func (t *ScalarMultTable) Compute(p *Point) { + t.t().Compute(p.e()) +} diff --git a/vendor/github.com/bwesterb/go-ristretto/scalar.go b/vendor/github.com/bwesterb/go-ristretto/scalar.go new file mode 100644 index 0000000000..487260ffad --- /dev/null +++ b/vendor/github.com/bwesterb/go-ristretto/scalar.go @@ -0,0 +1,1416 @@ +package ristretto + +import ( + "crypto/rand" + "crypto/sha512" + "encoding/base64" + "fmt" + + // Required for FieldElement.[Set]BigInt(). Obviously not used for actual + // implementation, as operations on big.Ints are not constant-time. + "math/big" +) + +// A number modulo the prime l, where l is the order of the Ristretto group +// over Edwards25519. +// +// The scalar s is represented as an array s[0], ... s[7] with 0 <= s[i] < 2^32 +// and s = s[0] + s[1] * 2^32 + s[2] * 2^64 + ... + s[7] * 2^224. +type Scalar [8]uint32 + +var ( + scZero Scalar + scOne = Scalar{ + 1, 0, 0, 0, 0, 0, 0, 0, + } + scL = Scalar{ + 0x5cf5d3ed, 0x5812631a, 0xa2f79cd6, 0x14def9de, + 0x00000000, 0x00000000, 0x00000000, 0x10000000, + } +) + +// Encode s little endian into buf. Returns s. +func (s *Scalar) BytesInto(buf *[32]byte) *Scalar { + buf[0] = uint8(s[0]) + buf[1] = uint8(s[0] >> 8) + buf[2] = uint8(s[0] >> 16) + buf[3] = uint8(s[0] >> 24) + buf[4] = uint8(s[1]) + buf[5] = uint8(s[1] >> 8) + buf[6] = uint8(s[1] >> 16) + buf[7] = uint8(s[1] >> 24) + buf[8] = uint8(s[2]) + buf[9] = uint8(s[2] >> 8) + buf[10] = uint8(s[2] >> 16) + buf[11] = uint8(s[2] >> 24) + buf[12] = uint8(s[3]) + buf[13] = uint8(s[3] >> 8) + buf[14] = uint8(s[3] >> 16) + buf[15] = uint8(s[3] >> 24) + buf[16] = uint8(s[4]) + buf[17] = uint8(s[4] >> 8) + buf[18] = uint8(s[4] >> 16) + buf[19] = uint8(s[4] >> 24) + buf[20] = uint8(s[5]) + buf[21] = uint8(s[5] >> 8) + buf[22] = uint8(s[5] >> 16) + buf[23] = uint8(s[5] >> 24) + buf[24] = uint8(s[6]) + buf[25] = uint8(s[6] >> 8) + buf[26] = uint8(s[6] >> 16) + buf[27] = uint8(s[6] >> 24) + buf[28] = uint8(s[7]) + buf[29] = uint8(s[7] >> 8) + buf[30] = uint8(s[7] >> 16) + buf[31] = uint8(s[7] >> 24) + return s +} + +// Bytes() returns a little-endian packed version of s. See also BytesInto(). +func (s *Scalar) Bytes() []byte { + var ret [32]byte + s.BytesInto(&ret) + return ret[:] +} + +// Sets s to x mod l, where x is interpreted little endian and the +// top 3 bits are ignored. Returns s. +func (s *Scalar) SetBytes(x *[32]byte) *Scalar { + s[0] = load4u32(x[0:]) + s[1] = load4u32(x[4:]) + s[2] = load4u32(x[8:]) + s[3] = load4u32(x[12:]) + s[4] = load4u32(x[16:]) + s[5] = load4u32(x[20:]) + s[6] = load4u32(x[24:]) + s[7] = load4u32(x[28:]) & 0x1fffffff + return s.Sub(s, &scL) +} + +// Sets s to -a. Returns s. +func (s *Scalar) Neg(a *Scalar) *Scalar { + return s.Sub(&scZero, a) +} + +// Sets s to a + b. Returns s. +func (s *Scalar) Add(a, b *Scalar) *Scalar { + carry := uint64(a[0]) + uint64(b[0]) + s[0] = uint32(carry) + carry = uint64(a[1]) + uint64(b[1]) + (carry >> 32) + s[1] = uint32(carry) + carry = uint64(a[2]) + uint64(b[2]) + (carry >> 32) + s[2] = uint32(carry) + carry = uint64(a[3]) + uint64(b[3]) + (carry >> 32) + s[3] = uint32(carry) + carry = uint64(a[4]) + uint64(b[4]) + (carry >> 32) + s[4] = uint32(carry) + carry = uint64(a[5]) + uint64(b[5]) + (carry >> 32) + s[5] = uint32(carry) + carry = uint64(a[6]) + uint64(b[6]) + (carry >> 32) + s[6] = uint32(carry) + carry = uint64(a[7]) + uint64(b[7]) + (carry >> 32) + s[7] = uint32(carry) + return s.Sub(s, &scL) +} + +// Sets s to a - b. Returns s. +func (s *Scalar) Sub(a, b *Scalar) *Scalar { + borrow := uint64(a[0]) - uint64(b[0]) + s0 := uint32(borrow) + borrow = uint64(a[1]) - uint64(b[1]) - (borrow >> 63) + s1 := uint32(borrow) + borrow = uint64(a[2]) - uint64(b[2]) - (borrow >> 63) + s2 := uint32(borrow) + borrow = uint64(a[3]) - uint64(b[3]) - (borrow >> 63) + s3 := uint32(borrow) + borrow = uint64(a[4]) - uint64(b[4]) - (borrow >> 63) + s4 := uint32(borrow) + borrow = uint64(a[5]) - uint64(b[5]) - (borrow >> 63) + s5 := uint32(borrow) + borrow = uint64(a[6]) - uint64(b[6]) - (borrow >> 63) + s6 := uint32(borrow) + borrow = uint64(a[7]) - uint64(b[7]) - (borrow >> 63) + s7 := uint32(borrow) + + // Add l if underflown + ufMask := ((borrow >> 63) ^ 1) - 1 + carry := uint64(s0) + (ufMask & uint64(0x5CF5D3ED)) + s0 = uint32(carry) + carry = uint64(s1) + (carry >> 32) + (ufMask & uint64(0x5812631A)) + s1 = uint32(carry) + carry = uint64(s2) + (carry >> 32) + (ufMask & uint64(0xA2F79CD6)) + s2 = uint32(carry) + carry = uint64(s3) + (carry >> 32) + (ufMask & uint64(0x14DEF9DE)) + s3 = uint32(carry) + carry = uint64(s4) + (carry >> 32) + s4 = uint32(carry) + carry = uint64(s5) + (carry >> 32) + s5 = uint32(carry) + carry = uint64(s6) + (carry >> 32) + s6 = uint32(carry) + carry = uint64(s7) + (carry >> 32) + (ufMask & 0x10000000) + s7 = uint32(carry) + + s[0] = s0 + s[1] = s1 + s[2] = s2 + s[3] = s3 + s[4] = s4 + s[5] = s5 + s[6] = s6 + s[7] = s7 + + return s +} + +// Returns s as a big.Int. +// +// Warning: operations on big.Ints are not constant-time: do not use them +// for cryptography unless you're sure this is not an issue. +func (s *Scalar) BigInt() *big.Int { + var ret big.Int + var buf, rBuf [32]byte + s.BytesInto(&buf) + for i := 0; i < 32; i++ { + rBuf[i] = buf[31-i] + } + return ret.SetBytes(rBuf[:]) +} + +// Sets s to x modulo l. +// +// Warning: operations on big.Ints are not constant-time: do not use them +// for cryptography unless you're sure this is not an issue. +func (s *Scalar) SetBigInt(x *big.Int) *Scalar { + var v, biL big.Int + biL.SetString( + "1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16) + buf := v.Mod(x, &biL).Bytes() + var rBuf [32]byte + for i := 0; i < len(buf) && i < 32; i++ { + rBuf[i] = buf[len(buf)-i-1] + } + return s.SetBytes(&rBuf) +} + +// Sets s to t. Returns s. +func (s *Scalar) Set(t *Scalar) *Scalar { + copy(s[:], t[:]) + return s +} + +// Sets s to 0. Returns s. +func (s *Scalar) SetZero() *Scalar { + return s.Set(&scZero) +} + +// Sets s to 1. Returns s. +func (s *Scalar) SetOne() *Scalar { + return s.Set(&scOne) +} + +// Sets s to a * b - c. Returns s. +func (s *Scalar) MulSub(a, b, c *Scalar) *Scalar { + a0 := int64(a[0] & 0x1fffff) + a1 := int64(((a[0] >> 21) | (a[1] << 11)) & 0x1fffff) + a2 := int64((a[1] >> 10) & 0x1fffff) + a3 := int64(((a[1] >> 31) | (a[2] << 1)) & 0x1fffff) + a4 := int64(((a[2] >> 20) | (a[3] << 12)) & 0x1fffff) + a5 := int64((a[3] >> 9) & 0x1fffff) + a6 := int64(((a[3] >> 30) | (a[4] << 2)) & 0x1fffff) + a7 := int64(((a[4] >> 19) | (a[5] << 13)) & 0x1fffff) + a8 := int64((a[5] >> 8) & 0x1fffff) + a9 := int64(((a[5] >> 29) | (a[6] << 3)) & 0x1fffff) + a10 := int64(((a[6] >> 18) | (a[7] << 14)) & 0x1fffff) + a11 := int64((a[7] >> 7)) + + b0 := int64(b[0] & 0x1fffff) + b1 := int64(((b[0] >> 21) | (b[1] << 11)) & 0x1fffff) + b2 := int64((b[1] >> 10) & 0x1fffff) + b3 := int64(((b[1] >> 31) | (b[2] << 1)) & 0x1fffff) + b4 := int64(((b[2] >> 20) | (b[3] << 12)) & 0x1fffff) + b5 := int64((b[3] >> 9) & 0x1fffff) + b6 := int64(((b[3] >> 30) | (b[4] << 2)) & 0x1fffff) + b7 := int64(((b[4] >> 19) | (b[5] << 13)) & 0x1fffff) + b8 := int64((b[5] >> 8) & 0x1fffff) + b9 := int64(((b[5] >> 29) | (b[6] << 3)) & 0x1fffff) + b10 := int64(((b[6] >> 18) | (b[7] << 14)) & 0x1fffff) + b11 := int64((b[7] >> 7)) + + c0 := int64(c[0] & 0x1fffff) + c1 := int64(((c[0] >> 21) | (c[1] << 11)) & 0x1fffff) + c2 := int64((c[1] >> 10) & 0x1fffff) + c3 := int64(((c[1] >> 31) | (c[2] << 1)) & 0x1fffff) + c4 := int64(((c[2] >> 20) | (c[3] << 12)) & 0x1fffff) + c5 := int64((c[3] >> 9) & 0x1fffff) + c6 := int64(((c[3] >> 30) | (c[4] << 2)) & 0x1fffff) + c7 := int64(((c[4] >> 19) | (c[5] << 13)) & 0x1fffff) + c8 := int64((c[5] >> 8) & 0x1fffff) + c9 := int64(((c[5] >> 29) | (c[6] << 3)) & 0x1fffff) + c10 := int64(((c[6] >> 18) | (c[7] << 14)) & 0x1fffff) + c11 := int64((c[7] >> 7)) + + return s.reduceAfterMul( + -c0+a0*b0, + -c1+a0*b1+a1*b0, + -c2+a0*b2+a1*b1+a2*b0, + -c3+a0*b3+a1*b2+a2*b1+a3*b0, + -c4+a0*b4+a1*b3+a2*b2+a3*b1+a4*b0, + -c5+a0*b5+a1*b4+a2*b3+a3*b2+a4*b1+a5*b0, + -c6+a0*b6+a1*b5+a2*b4+a3*b3+a4*b2+a5*b1+a6*b0, + -c7+a0*b7+a1*b6+a2*b5+a3*b4+a4*b3+a5*b2+a6*b1+a7*b0, + -c8+a0*b8+a1*b7+a2*b6+a3*b5+a4*b4+a5*b3+a6*b2+a7*b1+a8*b0, + -c9+a0*b9+a1*b8+a2*b7+a3*b6+a4*b5+a5*b4+a6*b3+a7*b2+a8*b1+a9*b0, + -c10+a0*b10+a1*b9+a2*b8+a3*b7+a4*b6+a5*b5+a6*b4+a7*b3+a8*b2+a9*b1+a10*b0, + -c11+a0*b11+a1*b10+a2*b9+a3*b8+a4*b7+a5*b6+a6*b5+a7*b4+a8*b3+a9*b2+a10*b1+a11*b0, + a1*b11+a2*b10+a3*b9+a4*b8+a5*b7+a6*b6+a7*b5+a8*b4+a9*b3+a10*b2+a11*b1, + a2*b11+a3*b10+a4*b9+a5*b8+a6*b7+a7*b6+a8*b5+a9*b4+a10*b3+a11*b2, + a3*b11+a4*b10+a5*b9+a6*b8+a7*b7+a8*b6+a9*b5+a10*b4+a11*b3, + a4*b11+a5*b10+a6*b9+a7*b8+a8*b7+a9*b6+a10*b5+a11*b4, + a5*b11+a6*b10+a7*b9+a8*b8+a9*b7+a10*b6+a11*b5, + a6*b11+a7*b10+a8*b9+a9*b8+a10*b7+a11*b6, + a7*b11+a8*b10+a9*b9+a10*b8+a11*b7, + a8*b11+a9*b10+a10*b9+a11*b8, + a9*b11+a10*b10+a11*b9, + a10*b11+a11*b10, + a11*b11) +} + +// Sets s to a * b + c. Returns s. +func (s *Scalar) MulAdd(a, b, c *Scalar) *Scalar { + a0 := int64(a[0] & 0x1fffff) + a1 := int64(((a[0] >> 21) | (a[1] << 11)) & 0x1fffff) + a2 := int64((a[1] >> 10) & 0x1fffff) + a3 := int64(((a[1] >> 31) | (a[2] << 1)) & 0x1fffff) + a4 := int64(((a[2] >> 20) | (a[3] << 12)) & 0x1fffff) + a5 := int64((a[3] >> 9) & 0x1fffff) + a6 := int64(((a[3] >> 30) | (a[4] << 2)) & 0x1fffff) + a7 := int64(((a[4] >> 19) | (a[5] << 13)) & 0x1fffff) + a8 := int64((a[5] >> 8) & 0x1fffff) + a9 := int64(((a[5] >> 29) | (a[6] << 3)) & 0x1fffff) + a10 := int64(((a[6] >> 18) | (a[7] << 14)) & 0x1fffff) + a11 := int64((a[7] >> 7)) + + b0 := int64(b[0] & 0x1fffff) + b1 := int64(((b[0] >> 21) | (b[1] << 11)) & 0x1fffff) + b2 := int64((b[1] >> 10) & 0x1fffff) + b3 := int64(((b[1] >> 31) | (b[2] << 1)) & 0x1fffff) + b4 := int64(((b[2] >> 20) | (b[3] << 12)) & 0x1fffff) + b5 := int64((b[3] >> 9) & 0x1fffff) + b6 := int64(((b[3] >> 30) | (b[4] << 2)) & 0x1fffff) + b7 := int64(((b[4] >> 19) | (b[5] << 13)) & 0x1fffff) + b8 := int64((b[5] >> 8) & 0x1fffff) + b9 := int64(((b[5] >> 29) | (b[6] << 3)) & 0x1fffff) + b10 := int64(((b[6] >> 18) | (b[7] << 14)) & 0x1fffff) + b11 := int64((b[7] >> 7)) + + c0 := int64(c[0] & 0x1fffff) + c1 := int64(((c[0] >> 21) | (c[1] << 11)) & 0x1fffff) + c2 := int64((c[1] >> 10) & 0x1fffff) + c3 := int64(((c[1] >> 31) | (c[2] << 1)) & 0x1fffff) + c4 := int64(((c[2] >> 20) | (c[3] << 12)) & 0x1fffff) + c5 := int64((c[3] >> 9) & 0x1fffff) + c6 := int64(((c[3] >> 30) | (c[4] << 2)) & 0x1fffff) + c7 := int64(((c[4] >> 19) | (c[5] << 13)) & 0x1fffff) + c8 := int64((c[5] >> 8) & 0x1fffff) + c9 := int64(((c[5] >> 29) | (c[6] << 3)) & 0x1fffff) + c10 := int64(((c[6] >> 18) | (c[7] << 14)) & 0x1fffff) + c11 := int64((c[7] >> 7)) + + return s.reduceAfterMul( + c0+a0*b0, + c1+a0*b1+a1*b0, + c2+a0*b2+a1*b1+a2*b0, + c3+a0*b3+a1*b2+a2*b1+a3*b0, + c4+a0*b4+a1*b3+a2*b2+a3*b1+a4*b0, + c5+a0*b5+a1*b4+a2*b3+a3*b2+a4*b1+a5*b0, + c6+a0*b6+a1*b5+a2*b4+a3*b3+a4*b2+a5*b1+a6*b0, + c7+a0*b7+a1*b6+a2*b5+a3*b4+a4*b3+a5*b2+a6*b1+a7*b0, + c8+a0*b8+a1*b7+a2*b6+a3*b5+a4*b4+a5*b3+a6*b2+a7*b1+a8*b0, + c9+a0*b9+a1*b8+a2*b7+a3*b6+a4*b5+a5*b4+a6*b3+a7*b2+a8*b1+a9*b0, + c10+a0*b10+a1*b9+a2*b8+a3*b7+a4*b6+a5*b5+a6*b4+a7*b3+a8*b2+a9*b1+a10*b0, + c11+a0*b11+a1*b10+a2*b9+a3*b8+a4*b7+a5*b6+a6*b5+a7*b4+a8*b3+a9*b2+a10*b1+a11*b0, + a1*b11+a2*b10+a3*b9+a4*b8+a5*b7+a6*b6+a7*b5+a8*b4+a9*b3+a10*b2+a11*b1, + a2*b11+a3*b10+a4*b9+a5*b8+a6*b7+a7*b6+a8*b5+a9*b4+a10*b3+a11*b2, + a3*b11+a4*b10+a5*b9+a6*b8+a7*b7+a8*b6+a9*b5+a10*b4+a11*b3, + a4*b11+a5*b10+a6*b9+a7*b8+a8*b7+a9*b6+a10*b5+a11*b4, + a5*b11+a6*b10+a7*b9+a8*b8+a9*b7+a10*b6+a11*b5, + a6*b11+a7*b10+a8*b9+a9*b8+a10*b7+a11*b6, + a7*b11+a8*b10+a9*b9+a10*b8+a11*b7, + a8*b11+a9*b10+a10*b9+a11*b8, + a9*b11+a10*b10+a11*b9, + a10*b11+a11*b10, + a11*b11) +} + +// Derive sets s to the half-length scalar derived from the given buffer +// using SHA512. Returns s +// +// Warning: half-length scalars are insecure in almost every application. +func (s *Scalar) DeriveShort(buf []byte) *Scalar { + h := sha512.Sum512(buf) + s[0] = load4u32(h[0:]) + s[1] = load4u32(h[4:]) + s[2] = load4u32(h[8:]) + s[3] = load4u32(h[12:]) + s[4] = 0 + s[5] = 0 + s[6] = 0 + s[7] = 0 + return s +} + +// Derive sets s to the scalar derived from the given buffer using SHA512 and +// Scalar.SetReduced() Returns s. +func (s *Scalar) Derive(buf []byte) *Scalar { + var sBuf [64]byte + h := sha512.Sum512(buf) + copy(sBuf[:], h[:]) + return s.SetReduced(&sBuf) +} + +// Sets s to t mod l, where t is interpreted little endian. Returns s. +func (s *Scalar) SetReduced(t *[64]byte) *Scalar { + t0 := 0x1FFFFF & load3(t[:]) + t1 := 0x1FFFFF & (load4(t[2:]) >> 5) + t2 := 0x1FFFFF & (load3(t[5:]) >> 2) + t3 := 0x1FFFFF & (load4(t[7:]) >> 7) + t4 := 0x1FFFFF & (load4(t[10:]) >> 4) + t5 := 0x1FFFFF & (load3(t[13:]) >> 1) + t6 := 0x1FFFFF & (load4(t[15:]) >> 6) + t7 := 0x1FFFFF & (load3(t[18:]) >> 3) + t8 := 0x1FFFFF & load3(t[21:]) + t9 := 0x1FFFFF & (load4(t[23:]) >> 5) + t10 := 0x1FFFFF & (load3(t[26:]) >> 2) + t11 := 0x1FFFFF & (load4(t[28:]) >> 7) + t12 := 0x1FFFFF & (load4(t[31:]) >> 4) + t13 := 0x1FFFFF & (load3(t[34:]) >> 1) + t14 := 0x1FFFFF & (load4(t[36:]) >> 6) + t15 := 0x1FFFFF & (load3(t[39:]) >> 3) + t16 := 0x1FFFFF & load3(t[42:]) + t17 := 0x1FFFFF & (load4(t[44:]) >> 5) + t18 := 0x1FFFFF & (load3(t[47:]) >> 2) + t19 := 0x1FFFFF & (load4(t[49:]) >> 7) + t20 := 0x1FFFFF & (load4(t[52:]) >> 4) + t21 := 0x1FFFFF & (load3(t[55:]) >> 1) + t22 := 0x1FFFFF & (load4(t[57:]) >> 6) + t23 := (load4(t[60:]) >> 3) + + t11 += t23 * 666643 + t12 += t23 * 470296 + t13 += t23 * 654183 + t14 -= t23 * 997805 + t15 += t23 * 136657 + t16 -= t23 * 683901 + t23 = 0 + + t10 += t22 * 666643 + t11 += t22 * 470296 + t12 += t22 * 654183 + t13 -= t22 * 997805 + t14 += t22 * 136657 + t15 -= t22 * 683901 + t22 = 0 + + t9 += t21 * 666643 + t10 += t21 * 470296 + t11 += t21 * 654183 + t12 -= t21 * 997805 + t13 += t21 * 136657 + t14 -= t21 * 683901 + t21 = 0 + + t8 += t20 * 666643 + t9 += t20 * 470296 + t10 += t20 * 654183 + t11 -= t20 * 997805 + t12 += t20 * 136657 + t13 -= t20 * 683901 + t20 = 0 + + t7 += t19 * 666643 + t8 += t19 * 470296 + t9 += t19 * 654183 + t10 -= t19 * 997805 + t11 += t19 * 136657 + t12 -= t19 * 683901 + t19 = 0 + + t6 += t18 * 666643 + t7 += t18 * 470296 + t8 += t18 * 654183 + t9 -= t18 * 997805 + t10 += t18 * 136657 + t11 -= t18 * 683901 + t18 = 0 + + var carry [17]int64 + + carry[6] = (t6 + (1 << 20)) >> 21 + t7 += carry[6] + t6 -= carry[6] << 21 + carry[8] = (t8 + (1 << 20)) >> 21 + t9 += carry[8] + t8 -= carry[8] << 21 + carry[10] = (t10 + (1 << 20)) >> 21 + t11 += carry[10] + t10 -= carry[10] << 21 + carry[12] = (t12 + (1 << 20)) >> 21 + t13 += carry[12] + t12 -= carry[12] << 21 + carry[14] = (t14 + (1 << 20)) >> 21 + t15 += carry[14] + t14 -= carry[14] << 21 + carry[16] = (t16 + (1 << 20)) >> 21 + t17 += carry[16] + t16 -= carry[16] << 21 + + carry[7] = (t7 + (1 << 20)) >> 21 + t8 += carry[7] + t7 -= carry[7] << 21 + carry[9] = (t9 + (1 << 20)) >> 21 + t10 += carry[9] + t9 -= carry[9] << 21 + carry[11] = (t11 + (1 << 20)) >> 21 + t12 += carry[11] + t11 -= carry[11] << 21 + carry[13] = (t13 + (1 << 20)) >> 21 + t14 += carry[13] + t13 -= carry[13] << 21 + carry[15] = (t15 + (1 << 20)) >> 21 + t16 += carry[15] + t15 -= carry[15] << 21 + + t5 += t17 * 666643 + t6 += t17 * 470296 + t7 += t17 * 654183 + t8 -= t17 * 997805 + t9 += t17 * 136657 + t10 -= t17 * 683901 + t17 = 0 + + t4 += t16 * 666643 + t5 += t16 * 470296 + t6 += t16 * 654183 + t7 -= t16 * 997805 + t8 += t16 * 136657 + t9 -= t16 * 683901 + t16 = 0 + + t3 += t15 * 666643 + t4 += t15 * 470296 + t5 += t15 * 654183 + t6 -= t15 * 997805 + t7 += t15 * 136657 + t8 -= t15 * 683901 + t15 = 0 + + t2 += t14 * 666643 + t3 += t14 * 470296 + t4 += t14 * 654183 + t5 -= t14 * 997805 + t6 += t14 * 136657 + t7 -= t14 * 683901 + t14 = 0 + + t1 += t13 * 666643 + t2 += t13 * 470296 + t3 += t13 * 654183 + t4 -= t13 * 997805 + t5 += t13 * 136657 + t6 -= t13 * 683901 + t13 = 0 + + t0 += t12 * 666643 + t1 += t12 * 470296 + t2 += t12 * 654183 + t3 -= t12 * 997805 + t4 += t12 * 136657 + t5 -= t12 * 683901 + t12 = 0 + + carry[0] = (t0 + (1 << 20)) >> 21 + t1 += carry[0] + t0 -= carry[0] << 21 + carry[2] = (t2 + (1 << 20)) >> 21 + t3 += carry[2] + t2 -= carry[2] << 21 + carry[4] = (t4 + (1 << 20)) >> 21 + t5 += carry[4] + t4 -= carry[4] << 21 + carry[6] = (t6 + (1 << 20)) >> 21 + t7 += carry[6] + t6 -= carry[6] << 21 + carry[8] = (t8 + (1 << 20)) >> 21 + t9 += carry[8] + t8 -= carry[8] << 21 + carry[10] = (t10 + (1 << 20)) >> 21 + t11 += carry[10] + t10 -= carry[10] << 21 + + carry[1] = (t1 + (1 << 20)) >> 21 + t2 += carry[1] + t1 -= carry[1] << 21 + carry[3] = (t3 + (1 << 20)) >> 21 + t4 += carry[3] + t3 -= carry[3] << 21 + carry[5] = (t5 + (1 << 20)) >> 21 + t6 += carry[5] + t5 -= carry[5] << 21 + carry[7] = (t7 + (1 << 20)) >> 21 + t8 += carry[7] + t7 -= carry[7] << 21 + carry[9] = (t9 + (1 << 20)) >> 21 + t10 += carry[9] + t9 -= carry[9] << 21 + carry[11] = (t11 + (1 << 20)) >> 21 + t12 += carry[11] + t11 -= carry[11] << 21 + + t0 += t12 * 666643 + t1 += t12 * 470296 + t2 += t12 * 654183 + t3 -= t12 * 997805 + t4 += t12 * 136657 + t5 -= t12 * 683901 + t12 = 0 + + carry[0] = t0 >> 21 + t1 += carry[0] + t0 -= carry[0] << 21 + carry[1] = t1 >> 21 + t2 += carry[1] + t1 -= carry[1] << 21 + carry[2] = t2 >> 21 + t3 += carry[2] + t2 -= carry[2] << 21 + carry[3] = t3 >> 21 + t4 += carry[3] + t3 -= carry[3] << 21 + carry[4] = t4 >> 21 + t5 += carry[4] + t4 -= carry[4] << 21 + carry[5] = t5 >> 21 + t6 += carry[5] + t5 -= carry[5] << 21 + carry[6] = t6 >> 21 + t7 += carry[6] + t6 -= carry[6] << 21 + carry[7] = t7 >> 21 + t8 += carry[7] + t7 -= carry[7] << 21 + carry[8] = t8 >> 21 + t9 += carry[8] + t8 -= carry[8] << 21 + carry[9] = t9 >> 21 + t10 += carry[9] + t9 -= carry[9] << 21 + carry[10] = t10 >> 21 + t11 += carry[10] + t10 -= carry[10] << 21 + carry[11] = t11 >> 21 + t12 += carry[11] + t11 -= carry[11] << 21 + + t0 += t12 * 666643 + t1 += t12 * 470296 + t2 += t12 * 654183 + t3 -= t12 * 997805 + t4 += t12 * 136657 + t5 -= t12 * 683901 + t12 = 0 + + carry[0] = t0 >> 21 + t1 += carry[0] + t0 -= carry[0] << 21 + carry[1] = t1 >> 21 + t2 += carry[1] + t1 -= carry[1] << 21 + carry[2] = t2 >> 21 + t3 += carry[2] + t2 -= carry[2] << 21 + carry[3] = t3 >> 21 + t4 += carry[3] + t3 -= carry[3] << 21 + carry[4] = t4 >> 21 + t5 += carry[4] + t4 -= carry[4] << 21 + carry[5] = t5 >> 21 + t6 += carry[5] + t5 -= carry[5] << 21 + carry[6] = t6 >> 21 + t7 += carry[6] + t6 -= carry[6] << 21 + carry[7] = t7 >> 21 + t8 += carry[7] + t7 -= carry[7] << 21 + carry[8] = t8 >> 21 + t9 += carry[8] + t8 -= carry[8] << 21 + carry[9] = t9 >> 21 + t10 += carry[9] + t9 -= carry[9] << 21 + carry[10] = t10 >> 21 + t11 += carry[10] + t10 -= carry[10] << 21 + + s[0] = uint32(t0) | uint32(t1<<21) + s[1] = uint32(t1>>11) | uint32(t2<<10) | uint32(t3<<31) + s[2] = uint32(t3>>1) | uint32(t4<<20) + s[3] = uint32(t4>>12) | uint32(t5<<9) | uint32(t6<<30) + s[4] = uint32(t6>>2) | uint32(t7<<19) + s[5] = uint32(t7>>13) | uint32(t8<<8) | uint32(t9<<29) + s[6] = uint32(t9>>3) | uint32(t10<<18) + s[7] = uint32(t10>>14) | uint32(t11<<7) + + return s +} + +// Sets s to a random scalar. Returns s. +func (s *Scalar) Rand() *Scalar { + var buf [64]byte + rand.Read(buf[:]) + return s.SetReduced(&buf) +} + +// Sets s to a*a. Returns s. +func (s *Scalar) Square(a *Scalar) *Scalar { + a0 := int64(a[0] & 0x1fffff) + a1 := int64(((a[0] >> 21) | (a[1] << 11)) & 0x1fffff) + a2 := int64((a[1] >> 10) & 0x1fffff) + a3 := int64(((a[1] >> 31) | (a[2] << 1)) & 0x1fffff) + a4 := int64(((a[2] >> 20) | (a[3] << 12)) & 0x1fffff) + a5 := int64((a[3] >> 9) & 0x1fffff) + a6 := int64(((a[3] >> 30) | (a[4] << 2)) & 0x1fffff) + a7 := int64(((a[4] >> 19) | (a[5] << 13)) & 0x1fffff) + a8 := int64((a[5] >> 8) & 0x1fffff) + a9 := int64(((a[5] >> 29) | (a[6] << 3)) & 0x1fffff) + a10 := int64(((a[6] >> 18) | (a[7] << 14)) & 0x1fffff) + a11 := int64((a[7] >> 7)) + + return s.reduceAfterMul( + a0*a0, + 2*a0*a1, + 2*a0*a2+a1*a1, + 2*(a0*a3+a1*a2), + 2*(a0*a4+a1*a3)+a2*a2, + 2*(a0*a5+a1*a4+a2*a3), + 2*(a0*a6+a1*a5+a2*a4)+a3*a3, + 2*(a0*a7+a1*a6+a2*a5+a3*a4), + 2*(a0*a8+a1*a7+a2*a6+a3*a5)+a4*a4, + 2*(a0*a9+a1*a8+a2*a7+a3*a6+a4*a5), + 2*(a0*a10+a1*a9+a2*a8+a3*a7+a4*a6)+a5*a5, + 2*(a0*a11+a1*a10+a2*a9+a3*a8+a4*a7+a5*a6), + 2*(a1*a11+a2*a10+a3*a9+a4*a8+a5*a7)+a6*a6, + 2*(a2*a11+a3*a10+a4*a9+a5*a8+a6*a7), + 2*(a3*a11+a4*a10+a5*a9+a6*a8)+a7*a7, + 2*(a4*a11+a5*a10+a6*a9+a7*a8), + 2*(a5*a11+a6*a10+a7*a9)+a8*a8, + 2*(a6*a11+a7*a10+a8*a9), + 2*(a7*a11+a8*a10)+a9*a9, + 2*(a8*a11+a9*a10), + 2*a9*a11+a10*a10, + 2*a10*a11, + a11*a11) +} + +// Sets s to a * b. Returns s. +func (s *Scalar) Mul(a, b *Scalar) *Scalar { + a0 := int64(a[0] & 0x1fffff) + a1 := int64(((a[0] >> 21) | (a[1] << 11)) & 0x1fffff) + a2 := int64((a[1] >> 10) & 0x1fffff) + a3 := int64(((a[1] >> 31) | (a[2] << 1)) & 0x1fffff) + a4 := int64(((a[2] >> 20) | (a[3] << 12)) & 0x1fffff) + a5 := int64((a[3] >> 9) & 0x1fffff) + a6 := int64(((a[3] >> 30) | (a[4] << 2)) & 0x1fffff) + a7 := int64(((a[4] >> 19) | (a[5] << 13)) & 0x1fffff) + a8 := int64((a[5] >> 8) & 0x1fffff) + a9 := int64(((a[5] >> 29) | (a[6] << 3)) & 0x1fffff) + a10 := int64(((a[6] >> 18) | (a[7] << 14)) & 0x1fffff) + a11 := int64((a[7] >> 7)) + + b0 := int64(b[0] & 0x1fffff) + b1 := int64(((b[0] >> 21) | (b[1] << 11)) & 0x1fffff) + b2 := int64((b[1] >> 10) & 0x1fffff) + b3 := int64(((b[1] >> 31) | (b[2] << 1)) & 0x1fffff) + b4 := int64(((b[2] >> 20) | (b[3] << 12)) & 0x1fffff) + b5 := int64((b[3] >> 9) & 0x1fffff) + b6 := int64(((b[3] >> 30) | (b[4] << 2)) & 0x1fffff) + b7 := int64(((b[4] >> 19) | (b[5] << 13)) & 0x1fffff) + b8 := int64((b[5] >> 8) & 0x1fffff) + b9 := int64(((b[5] >> 29) | (b[6] << 3)) & 0x1fffff) + b10 := int64(((b[6] >> 18) | (b[7] << 14)) & 0x1fffff) + b11 := int64((b[7] >> 7)) + + return s.reduceAfterMul( + a0*b0, + a0*b1+a1*b0, + a0*b2+a1*b1+a2*b0, + a0*b3+a1*b2+a2*b1+a3*b0, + a0*b4+a1*b3+a2*b2+a3*b1+a4*b0, + a0*b5+a1*b4+a2*b3+a3*b2+a4*b1+a5*b0, + a0*b6+a1*b5+a2*b4+a3*b3+a4*b2+a5*b1+a6*b0, + a0*b7+a1*b6+a2*b5+a3*b4+a4*b3+a5*b2+a6*b1+a7*b0, + a0*b8+a1*b7+a2*b6+a3*b5+a4*b4+a5*b3+a6*b2+a7*b1+a8*b0, + a0*b9+a1*b8+a2*b7+a3*b6+a4*b5+a5*b4+a6*b3+a7*b2+a8*b1+a9*b0, + a0*b10+a1*b9+a2*b8+a3*b7+a4*b6+a5*b5+a6*b4+a7*b3+a8*b2+a9*b1+a10*b0, + a0*b11+a1*b10+a2*b9+a3*b8+a4*b7+a5*b6+a6*b5+a7*b4+a8*b3+a9*b2+a10*b1+a11*b0, + a1*b11+a2*b10+a3*b9+a4*b8+a5*b7+a6*b6+a7*b5+a8*b4+a9*b3+a10*b2+a11*b1, + a2*b11+a3*b10+a4*b9+a5*b8+a6*b7+a7*b6+a8*b5+a9*b4+a10*b3+a11*b2, + a3*b11+a4*b10+a5*b9+a6*b8+a7*b7+a8*b6+a9*b5+a10*b4+a11*b3, + a4*b11+a5*b10+a6*b9+a7*b8+a8*b7+a9*b6+a10*b5+a11*b4, + a5*b11+a6*b10+a7*b9+a8*b8+a9*b7+a10*b6+a11*b5, + a6*b11+a7*b10+a8*b9+a9*b8+a10*b7+a11*b6, + a7*b11+a8*b10+a9*b9+a10*b8+a11*b7, + a8*b11+a9*b10+a10*b9+a11*b8, + a9*b11+a10*b10+a11*b9, + a10*b11+a11*b10, + a11*b11) +} + +// Sets s to 1/t. Returns s. +func (s *Scalar) Inverse(t *Scalar) *Scalar { + var t0, t1, t2, t3, t4, t5 Scalar + + t1.Square(t) + t2.Mul(t, &t1) + t0.Mul(&t1, &t2) + t1.Square(&t0) + t3.Square(&t1) + t1.Mul(&t2, &t3) + t2.Square(&t1) + t3.Mul(&t0, &t2) + t0.Square(&t3) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t1.Mul(&t2, &t0) + t0.Square(&t1) + t1.Mul(&t3, &t0) + t0.Square(&t1) + t3.Square(&t0) + t0.Mul(&t1, &t3) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t1.Mul(&t3, &t0) + t0.Square(&t1) + t3.Mul(&t1, &t0) + t0.Mul(&t2, &t3) + t2.Mul(&t1, &t0) + t1.Square(&t2) + t3.Square(&t1) + t4.Square(&t3) + t3.Mul(&t1, &t4) + t1.Mul(&t0, &t3) + t0.Mul(&t2, &t1) + t2.Mul(&t1, &t0) + t1.Square(&t2) + t3.Square(&t1) + t1.Mul(&t0, &t3) + t0.Square(&t1) + t3.Square(&t0) + t0.Mul(&t1, &t3) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t1.Square(&t0) + t0.Mul(&t2, &t1) + t1.Mul(&t3, &t0) + t0.Square(&t1) + t3.Square(&t0) + t0.Square(&t3) + t3.Square(&t0) + t0.Square(&t3) + t3.Square(&t0) + t0.Mul(&t1, &t3) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t1.Mul(&t2, &t0) + t0.Square(&t1) + t4.Mul(&t2, &t0) + t0.Square(&t4) + t4.Square(&t0) + t0.Mul(&t1, &t4) + t1.Mul(&t3, &t0) + t0.Square(&t1) + t3.Mul(&t1, &t0) + t0.Square(&t3) + t4.Square(&t0) + t0.Mul(&t3, &t4) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Square(&t0) + t0.Square(&t2) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t1.Mul(&t3, &t0) + t0.Mul(&t2, &t1) + t2.Mul(&t1, &t0) + t1.Square(&t2) + t3.Square(&t1) + t1.Mul(&t0, &t3) + t0.Square(&t1) + t3.Mul(&t2, &t0) + t0.Mul(&t1, &t3) + t1.Square(&t0) + t2.Square(&t1) + t1.Mul(&t0, &t2) + t2.Mul(&t3, &t1) + t1.Mul(&t0, &t2) + t0.Mul(&t2, &t1) + t2.Square(&t0) + t3.Mul(&t0, &t2) + t2.Square(&t3) + t3.Mul(&t1, &t2) + t1.Mul(&t0, &t3) + t0.Square(&t1) + t2.Mul(&t1, &t0) + t0.Square(&t2) + t4.Mul(&t2, &t0) + t0.Square(&t4) + t4.Square(&t0) + t5.Square(&t4) + t4.Square(&t5) + t5.Square(&t4) + t4.Square(&t5) + t5.Mul(&t0, &t4) + t0.Mul(&t2, &t5) + t2.Mul(&t3, &t0) + t0.Mul(&t1, &t2) + t1.Square(&t0) + t3.Mul(&t0, &t1) + t1.Square(&t3) + t4.Mul(&t0, &t1) + t1.Square(&t4) + t4.Square(&t1) + t1.Square(&t4) + t4.Mul(&t3, &t1) + t1.Mul(&t2, &t4) + t2.Square(&t1) + t3.Square(&t2) + t4.Square(&t3) + t3.Mul(&t2, &t4) + t2.Mul(&t1, &t3) + t3.Mul(&t0, &t2) + t0.Square(&t3) + t2.Square(&t0) + t0.Square(&t2) + t2.Mul(&t1, &t0) + t0.Mul(&t3, &t2) + t1.Square(&t0) + t3.Square(&t1) + t4.Mul(&t1, &t3) + t3.Square(&t4) + t4.Square(&t3) + t3.Mul(&t1, &t4) + t1.Mul(&t2, &t3) + t2.Square(&t1) + t3.Square(&t2) + t2.Mul(&t0, &t3) + t0.Square(&t2) + t3.Mul(&t1, &t0) + t0.Square(&t3) + t1.Mul(&t2, &t0) + t0.Mul(&t3, &t1) + t2.Square(&t0) + t3.Square(&t2) + t2.Square(&t3) + t3.Square(&t2) + t2.Mul(&t1, &t3) + t1.Mul(&t0, &t2) + t0.Square(&t1) + t3.Square(&t0) + t4.Square(&t3) + t3.Mul(&t0, &t4) + t0.Mul(&t1, &t3) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Square(&t0) + t0.Mul(&t1, &t2) + t1.Square(&t0) + t2.Mul(&t3, &t1) + t1.Mul(&t0, &t2) + t0.Square(&t1) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t2.Square(&t0) + t0.Mul(&t1, &t2) + t1.Mul(&t3, &t0) + t2.Square(&t1) + t3.Mul(&t0, &t2) + t0.Mul(&t1, &t3) + t1.Square(&t0) + t2.Square(&t1) + t4.Square(&t2) + t2.Mul(&t1, &t4) + t4.Square(&t2) + t2.Square(&t4) + t4.Square(&t2) + t2.Mul(&t1, &t4) + t1.Mul(&t3, &t2) + t2.Square(&t1) + t3.Square(&t2) + t2.Mul(&t1, &t3) + t3.Square(&t2) + t2.Square(&t3) + t3.Mul(&t1, &t2) + t2.Mul(&t0, &t3) + t0.Square(&t2) + t3.Mul(&t2, &t0) + t0.Square(&t3) + t4.Square(&t0) + t0.Mul(&t3, &t4) + t3.Mul(&t1, &t0) + t0.Square(&t3) + t1.Mul(&t3, &t0) + t0.Mul(&t2, &t1) + for i := 0; i < 126; i++ { + t0.Square(&t0) + } + s.Mul(&t3, &t0) + return s +} + +// IsNonZeroI returns 1 if s is non-zero and 0 otherwise. +func (s *Scalar) IsNonZeroI() int32 { + ret := s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] + ret |= ret >> 16 + ret |= ret >> 8 + ret |= ret >> 4 + ret |= ret >> 2 + ret |= ret >> 1 + return int32(ret & 1) +} + +// EqualsI returns 1 if s is equal to a, otherwise 0. +func (s *Scalar) EqualsI(a *Scalar) int32 { + var b Scalar + return 1 - b.Sub(s, a).IsNonZeroI() +} + +// Equals returns whether s is equal to a. +func (s *Scalar) Equals(a *Scalar) bool { + var b Scalar + return b.Sub(s, a).IsNonZeroI() == 0 +} + +// Implements encoding/BinaryUnmarshaler. Use SetBytes, if convenient, instead. +func (s *Scalar) UnmarshalBinary(data []byte) error { + if len(data) != 32 { + return fmt.Errorf("ristretto.Scalar should be 32 bytes; not %d", len(data)) + } + var buf [32]byte + copy(buf[:], data) + s.SetBytes(&buf) + return nil +} + +// Implements encoding/BinaryMarshaler. Use BytesInto, if convenient, instead. +func (s *Scalar) MarshalBinary() ([]byte, error) { + var buf [32]byte + s.BytesInto(&buf) + return buf[:], nil +} + +func (s *Scalar) MarshalText() ([]byte, error) { + enc := base64.RawURLEncoding + var buf [32]byte + s.BytesInto(&buf) + ret := make([]byte, enc.EncodedLen(32)) + enc.Encode(ret, buf[:]) + return ret, nil +} + +func (s *Scalar) UnmarshalText(txt []byte) error { + enc := base64.RawURLEncoding + var buf [32]byte + n, err := enc.Decode(buf[:], txt) + if err != nil { + return err + } + if n != 32 { + return fmt.Errorf("ristretto.Scalar should be 32 bytes; not %d", n) + } + s.SetBytes(&buf) + return nil +} + +func (s Scalar) String() string { + text, _ := s.MarshalText() + return string(text) +} + +// Interprets a 3-byte unsigned little endian byte-slice as int64 +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +// Interprets a 4-byte unsigned little endian byte-slice as int64 +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +// Interprets a 4-byte unsigned little endian byte-slice as uint32 +func load4u32(in []byte) uint32 { + return (uint32(in[0]) | (uint32(in[1]) << 8) | + (uint32(in[2]) << 16) | (uint32(in[3]) << 24)) +} + +// Sets s to s0 + s1 * 2^21 + s2 * 2^(21*2) + ... + s22 * s^(21*22) modulo l. +// Requires |s_i| to be sufficiently small (< ~2^42). Used in Mul, Square, etc. +func (s *Scalar) reduceAfterMul(s0, s1, s2, s3, s4, s5, s6, s7, + s8, s9, s10, s11, s12, s13, s14, s15, s16, + s17, s18, s19, s20, s21, s22 int64) *Scalar { + var s23 int64 = 0 + var carry [23]int64 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + carry[18] = (s18 + (1 << 20)) >> 21 + s19 += carry[18] + s18 -= carry[18] << 21 + carry[20] = (s20 + (1 << 20)) >> 21 + s21 += carry[20] + s20 -= carry[20] << 21 + carry[22] = (s22 + (1 << 20)) >> 21 + s23 += carry[22] + s22 -= carry[22] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + carry[17] = (s17 + (1 << 20)) >> 21 + s18 += carry[17] + s17 -= carry[17] << 21 + carry[19] = (s19 + (1 << 20)) >> 21 + s20 += carry[19] + s19 -= carry[19] << 21 + carry[21] = (s21 + (1 << 20)) >> 21 + s22 += carry[21] + s21 -= carry[21] << 21 + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + s[0] = uint32(s0) | uint32(s1<<21) + s[1] = uint32(s1>>11) | uint32(s2<<10) | uint32(s3<<31) + s[2] = uint32(s3>>1) | uint32(s4<<20) + s[3] = uint32(s4>>12) | uint32(s5<<9) | uint32(s6<<30) + s[4] = uint32(s6>>2) | uint32(s7<<19) + s[5] = uint32(s7>>13) | uint32(s8<<8) | uint32(s9<<29) + s[6] = uint32(s9>>3) | uint32(s10<<18) + s[7] = uint32(s10>>14) | uint32(s11<<7) + return s +} diff --git a/vendor/github.com/coinbase/kryptology/LICENSE b/vendor/github.com/coinbase/kryptology/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/coinbase/kryptology/NOTICE b/vendor/github.com/coinbase/kryptology/NOTICE new file mode 100644 index 0000000000..62abaec238 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/NOTICE @@ -0,0 +1,5 @@ +Coinbase Kryptology +Copyright [2021] contributors to Coinbase Kryptology + +This product includes software developed at +Coinbase (http://www.coinbase.com/). diff --git a/vendor/github.com/coinbase/kryptology/internal/err.go b/vendor/github.com/coinbase/kryptology/internal/err.go new file mode 100644 index 0000000000..2ea5082cb8 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/internal/err.go @@ -0,0 +1,22 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package internal + +import "fmt" + +var ( + ErrNotOnCurve = fmt.Errorf("point not on the curve") + ErrPointsDistinctCurves = fmt.Errorf("points must be from the same curve") + ErrZmMembership = fmt.Errorf("x ∉ Z_m") + ErrResidueOne = fmt.Errorf("value must be 1 (mod N)") + ErrNCannotBeZero = fmt.Errorf("N cannot be 0") + ErrNilArguments = fmt.Errorf("arguments cannot be nil") + ErrZeroValue = fmt.Errorf("arguments cannot be 0") + ErrInvalidRound = fmt.Errorf("invalid round method called") + ErrIncorrectCount = fmt.Errorf("incorrect number of inputs") + ErrInvalidJson = fmt.Errorf("json format does not contain the necessary data") +) diff --git a/vendor/github.com/coinbase/kryptology/internal/hash.go b/vendor/github.com/coinbase/kryptology/internal/hash.go new file mode 100644 index 0000000000..6320ea5999 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/internal/hash.go @@ -0,0 +1,93 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package internal + +import ( + "bytes" + "crypto/sha256" + "fmt" + + "golang.org/x/crypto/hkdf" +) + +// Hash computes the HKDF over many values +// iteratively such that each value is hashed separately +// and based on preceding values +// +// The first value is computed as okm_0 = KDF(f || value) where +// f is a byte slice of 32 0xFF +// salt is zero-filled byte slice with length equal to the hash output length +// info is the protocol name +// okm is the 32 byte output +// +// The each subsequent iteration is computed by as okm_i = KDF(f_i || value || okm_{i-1}) +// where f_i = 2^b - 1 - i such that there are 0xFF bytes prior to the value. +// f_1 changes the first byte to 0xFE, f_2 to 0xFD. The previous okm is appended to the value +// to provide cryptographic domain separation. +// See https://signal.org/docs/specifications/x3dh/#cryptographic-notation +// and https://signal.org/docs/specifications/xeddsa/#hash-functions +// for more details. +// This uses the KDF function similar to X3DH for each `value` +// But changes the key just like XEdDSA where the prefix bytes change by a single bit +func Hash(info []byte, values ...[]byte) ([]byte, error) { + // Don't accept any nil arguments + if anyNil(values...) { + return nil, ErrNilArguments + } + + salt := make([]byte, 32) + okm := make([]byte, 32) + f := bytes.Repeat([]byte{0xFF}, 32) + + for _, b := range values { + ikm := append(f, b...) + ikm = append(ikm, okm...) + kdf := hkdf.New(sha256.New, ikm, salt, info) + n, err := kdf.Read(okm) + if err != nil { + return nil, err + } + if n != len(okm) { + return nil, fmt.Errorf("unable to read expected number of bytes want=%v got=%v", len(okm), n) + } + ByteSub(f) + } + return okm, nil +} + +func anyNil(values ...[]byte) bool { + for _, x := range values { + if x == nil { + return true + } + } + return false +} + +// ByteSub is a constant time algorithm for subtracting +// 1 from the array as if it were a big number. +// 0 is considered a wrap which resets to 0xFF +func ByteSub(b []byte) { + m := byte(1) + for i := 0; i < len(b); i++ { + b[i] -= m + + // If b[i] > 0, s == 0 + // If b[i] == 0, s == 1 + // Computing IsNonZero(b[i]) + s1 := int8(b[i]) >> 7 + s2 := -int8(b[i]) >> 7 + s := byte((s1 | s2) + 1) + + // If s == 0, don't subtract anymore + // s == 1, continue subtracting + m = s & m + // If s == 0 this does nothing + // If s == 1 reset this value to 0xFF + b[i] |= -s + } +} diff --git a/vendor/github.com/coinbase/kryptology/internal/point.go b/vendor/github.com/coinbase/kryptology/internal/point.go new file mode 100644 index 0000000000..6393e803a1 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/internal/point.go @@ -0,0 +1,44 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package internal + +import ( + "crypto/elliptic" + "math/big" + + "filippo.io/edwards25519" +) + +func CalcFieldSize(curve elliptic.Curve) int { + bits := curve.Params().BitSize + return (bits + 7) / 8 +} + +func ReverseScalarBytes(inBytes []byte) []byte { + outBytes := make([]byte, len(inBytes)) + + for i, j := 0, len(inBytes)-1; j >= 0; i, j = i+1, j-1 { + outBytes[i] = inBytes[j] + } + + return outBytes +} + +func BigInt2Ed25519Point(y *big.Int) (*edwards25519.Point, error) { + b := y.Bytes() + var arr [32]byte + copy(arr[32-len(b):], b) + return edwards25519.NewIdentityPoint().SetBytes(arr[:]) +} + +func BigInt2Ed25519Scalar(x *big.Int) (*edwards25519.Scalar, error) { + // big.Int is big endian; ed25519 assumes little endian encoding + kBytes := ReverseScalarBytes(x.Bytes()) + var arr [32]byte + copy(arr[:], kBytes) + return edwards25519.NewScalar().SetCanonicalBytes(arr[:]) +} diff --git a/vendor/github.com/coinbase/kryptology/internal/testutils.go b/vendor/github.com/coinbase/kryptology/internal/testutils.go new file mode 100644 index 0000000000..eec48970e6 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/internal/testutils.go @@ -0,0 +1,21 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package internal + +import ( + "math/big" +) + +// B10 creating a big.Int from a base 10 string. panics on failure to +// ensure zero-values aren't used in place of malformed strings. +func B10(s string) *big.Int { + x, ok := new(big.Int).SetString(s, 10) + if !ok { + panic("Couldn't derive big.Int from string") + } + return x +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/README.md b/vendor/github.com/coinbase/kryptology/pkg/core/README.md new file mode 100644 index 0000000000..dfb02d2eb0 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/README.md @@ -0,0 +1,5 @@ +# Core Package + +The core package contains a set of primitives, including but not limited to various +elliptic curves, hashes, and commitment schemes. These primitives are used internally +and can also be used independently on their own externally. diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/commit.go b/vendor/github.com/coinbase/kryptology/pkg/core/commit.go new file mode 100644 index 0000000000..8cfe0423b7 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/commit.go @@ -0,0 +1,115 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package core + +import ( + "crypto/hmac" + crand "crypto/rand" + "crypto/sha256" + "crypto/subtle" + "encoding/json" + "fmt" + "hash" +) + +// Size of random values and hash outputs are determined by our hash function +const Size = sha256.Size + +type ( + // Commitment to a given message which can be later revealed. + // This is sent to and held by a verifier until the corresponding + // witness is provided. + Commitment []byte + + // Witness is sent to and opened by the verifier. This proves that + // committed message hasn't been altered by later information. + Witness struct { + Msg []byte + r [Size]byte + } + + // witnessJSON is used for un/marshaling. + witnessJSON struct { + Msg []byte + R [Size]byte + } +) + +// MarshalJSON encodes Witness in JSON +func (w Witness) MarshalJSON() ([]byte, error) { + return json.Marshal(witnessJSON{w.Msg, w.r}) +} + +// UnmarshalJSON decodes JSON into a Witness struct +func (w *Witness) UnmarshalJSON(data []byte) error { + witness := &witnessJSON{} + err := json.Unmarshal(data, witness) + if err != nil { + return err + } + w.Msg = witness.Msg + w.r = witness.R + return nil +} + +// Commit to a given message. Uses SHA256 as the hash function. +func Commit(msg []byte) (Commitment, *Witness, error) { + // Initialize our decommitment + d := Witness{msg, [Size]byte{}} + + // Generate a random nonce of the required length + n, err := crand.Read(d.r[:]) + // Ensure no errors retrieving nonce + if err != nil { + return nil, nil, err + } + + // Ensure we read all the bytes expected + if n != Size { + return nil, nil, fmt.Errorf("failed to read %v bytes from crypto/rand: received %v bytes", Size, n) + } + // Compute the commitment: HMAC(Sha2, msg, key) + c, err := ComputeHMAC(sha256.New, msg, d.r[:]) + if err != nil { + return nil, nil, err + } + return c, &d, nil +} + +// Open a commitment and return true if the commitment/decommitment pair are valid. +// reference: spec.§2.4: Commitment Scheme +func Open(c Commitment, d Witness) (bool, error) { + // Ensure commitment is well-formed. + if len(c) != Size { + return false, fmt.Errorf("invalid commitment, wrong length. %v != %v", len(c), Size) + } + + // Re-compute the commitment: HMAC(Sha2, msg, key) + cʹ, err := ComputeHMAC(sha256.New, d.Msg, d.r[:]) + if err != nil { + return false, err + } + return subtle.ConstantTimeCompare(cʹ, c) == 1, nil +} + +// ComputeHMAC computes HMAC(hash_fn, msg, key) +// Takes in a hash function to use for HMAC +func ComputeHMAC(f func() hash.Hash, msg []byte, k []byte) ([]byte, error) { + if f == nil { + return nil, fmt.Errorf("hash function cannot be nil") + } + + mac := hmac.New(f, k) + w, err := mac.Write(msg) + + if w != len(msg) { + return nil, fmt.Errorf("bytes written to hash doesn't match expected: %v != %v", w, len(msg)) + } else if err != nil { + return nil, err + } + return mac.Sum(nil), nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/README.md b/vendor/github.com/coinbase/kryptology/pkg/core/curves/README.md new file mode 100644 index 0000000000..99760158b2 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/README.md @@ -0,0 +1,3 @@ +# Curves + +The curves package contains implementation of various elliptic curves. diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12377_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12377_curve.go new file mode 100644 index 0000000000..4bd181d7ae --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12377_curve.go @@ -0,0 +1,1224 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// NOTE that the bls curves are NOT constant time. There is an open issue to address it: https://github.com/coinbase/kryptology/issues/233 + +package curves + +import ( + "crypto/rand" + "crypto/sha256" + "crypto/subtle" + "fmt" + "io" + "math/big" + + bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" + "golang.org/x/crypto/sha3" + + "github.com/coinbase/kryptology/pkg/core" +) + +// See 'r' = https://eprint.iacr.org/2018/962.pdf Figure 16 +var bls12377modulus = bhex("12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001") +var g1Inf = bls12377.G1Affine{X: [6]uint64{}, Y: [6]uint64{}} +var g2Inf = bls12377.G2Affine{ + X: bls12377.E2{A0: [6]uint64{}, A1: [6]uint64{}}, + Y: bls12377.E2{A0: [6]uint64{}, A1: [6]uint64{}}, +} + +type ScalarBls12377 struct { + value *big.Int + point Point +} + +type PointBls12377G1 struct { + value *bls12377.G1Affine +} + +type PointBls12377G2 struct { + value *bls12377.G2Affine +} + +type ScalarBls12377Gt struct { + value *bls12377.GT +} + +func (s *ScalarBls12377) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarBls12377) Hash(bytes []byte) Scalar { + xmd, err := expandMsgXmd(sha256.New(), bytes, []byte("BLS12377_XMD:SHA-256_SSWU_RO_"), 48) + if err != nil { + return nil + } + v := new(big.Int).SetBytes(xmd) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } +} + +func (s *ScalarBls12377) Zero() Scalar { + return &ScalarBls12377{ + value: big.NewInt(0), + point: s.point, + } +} + +func (s *ScalarBls12377) One() Scalar { + return &ScalarBls12377{ + value: big.NewInt(1), + point: s.point, + } +} + +func (s *ScalarBls12377) IsZero() bool { + return subtle.ConstantTimeCompare(s.value.Bytes(), []byte{}) == 1 +} + +func (s *ScalarBls12377) IsOne() bool { + return subtle.ConstantTimeCompare(s.value.Bytes(), []byte{1}) == 1 +} + +func (s *ScalarBls12377) IsOdd() bool { + return s.value.Bit(0) == 1 +} + +func (s *ScalarBls12377) IsEven() bool { + return s.value.Bit(0) == 0 +} + +func (s *ScalarBls12377) New(value int) Scalar { + v := big.NewInt(int64(value)) + if value < 0 { + v.Mod(v, bls12377modulus) + } + return &ScalarBls12377{ + value: v, + point: s.point, + } +} + +func (s *ScalarBls12377) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarBls12377) + if ok { + return s.value.Cmp(r.value) + } else { + return -2 + } +} + +func (s *ScalarBls12377) Square() Scalar { + return &ScalarBls12377{ + value: new(big.Int).Exp(s.value, big.NewInt(2), bls12377modulus), + point: s.point, + } +} + +func (s *ScalarBls12377) Double() Scalar { + v := new(big.Int).Add(s.value, s.value) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } +} + +func (s *ScalarBls12377) Invert() (Scalar, error) { + return &ScalarBls12377{ + value: new(big.Int).ModInverse(s.value, bls12377modulus), + point: s.point, + }, nil +} + +func (s *ScalarBls12377) Sqrt() (Scalar, error) { + return &ScalarBls12377{ + value: new(big.Int).ModSqrt(s.value, bls12377modulus), + point: s.point, + }, nil +} + +func (s *ScalarBls12377) Cube() Scalar { + return &ScalarBls12377{ + value: new(big.Int).Exp(s.value, big.NewInt(3), bls12377modulus), + point: s.point, + } +} + +func (s *ScalarBls12377) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377) + if ok { + v := new(big.Int).Add(s.value, r.value) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12377) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377) + if ok { + v := new(big.Int).Sub(s.value, r.value) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12377) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377) + if ok { + v := new(big.Int).Mul(s.value, r.value) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12377) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarBls12377) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377) + if ok { + v := new(big.Int).ModInverse(r.value, bls12377modulus) + v.Mul(v, s.value) + return &ScalarBls12377{ + value: v.Mod(v, bls12377modulus), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12377) Neg() Scalar { + z := new(big.Int).Neg(s.value) + return &ScalarBls12377{ + value: z.Mod(z, bls12377modulus), + point: s.point, + } +} + +func (s *ScalarBls12377) SetBigInt(v *big.Int) (Scalar, error) { + if v == nil { + return nil, fmt.Errorf("invalid value") + } + t := new(big.Int).Mod(v, bls12377modulus) + if t.Cmp(v) != 0 { + return nil, fmt.Errorf("invalid value") + } + return &ScalarBls12377{ + value: t, + point: s.point, + }, nil +} + +func (s *ScalarBls12377) BigInt() *big.Int { + return new(big.Int).Set(s.value) +} + +func (s *ScalarBls12377) Bytes() []byte { + var out [32]byte + return s.value.FillBytes(out[:]) +} + +func (s *ScalarBls12377) SetBytes(bytes []byte) (Scalar, error) { + value := new(big.Int).SetBytes(bytes) + t := new(big.Int).Mod(value, bls12377modulus) + if t.Cmp(value) != 0 { + return nil, fmt.Errorf("invalid byte sequence") + } + return &ScalarBls12377{ + value: t, + point: s.point, + }, nil +} + +func (s *ScalarBls12377) SetBytesWide(bytes []byte) (Scalar, error) { + if len(bytes) < 32 || len(bytes) > 128 { + return nil, fmt.Errorf("invalid byte sequence") + } + value := new(big.Int).SetBytes(bytes) + t := new(big.Int).Mod(value, bls12377modulus) + return &ScalarBls12377{ + value: t, + point: s.point, + }, nil +} + +func (s *ScalarBls12377) Point() Point { + return s.point.Identity() +} + +func (s *ScalarBls12377) Clone() Scalar { + return &ScalarBls12377{ + value: new(big.Int).Set(s.value), + point: s.point, + } +} + +func (s *ScalarBls12377) SetPoint(p Point) PairingScalar { + return &ScalarBls12377{ + value: new(big.Int).Set(s.value), + point: p, + } +} + +func (s *ScalarBls12377) Order() *big.Int { + return bls12377modulus +} + +func (s *ScalarBls12377) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarBls12377) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12377) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + s.point = ss.point + return nil +} + +func (s *ScalarBls12377) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarBls12377) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12377) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + s.point = ss.point + return nil +} + +func (s *ScalarBls12377) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarBls12377) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarBls12377) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +func (p *PointBls12377G1) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointBls12377G1) Hash(bytes []byte) Point { + var domain = []byte("BLS12377G1_XMD:SHA-256_SVDW_RO_") + pt, err := bls12377.HashToCurveG1Svdw(bytes, domain) + if err != nil { + return nil + } + return &PointBls12377G1{value: &pt} +} + +func (p *PointBls12377G1) Identity() Point { + t := bls12377.G1Affine{} + return &PointBls12377G1{ + value: t.Set(&g1Inf), + } +} + +func (p *PointBls12377G1) Generator() Point { + t := bls12377.G1Affine{} + _, _, g1Aff, _ := bls12377.Generators() + return &PointBls12377G1{ + value: t.Set(&g1Aff), + } +} + +func (p *PointBls12377G1) IsIdentity() bool { + return p.value.IsInfinity() +} + +func (p *PointBls12377G1) IsNegative() bool { + // According to https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#serialization + // This bit represents the sign of the `y` coordinate which is what we want + + return (p.value.Bytes()[0]>>5)&1 == 1 +} + +func (p *PointBls12377G1) IsOnCurve() bool { + return p.value.IsOnCurve() +} + +func (p *PointBls12377G1) Double() Point { + t := &bls12377.G1Jac{} + t.FromAffine(p.value) + t.DoubleAssign() + value := bls12377.G1Affine{} + return &PointBls12377G1{value.FromJacobian(t)} +} + +func (p *PointBls12377G1) Scalar() Scalar { + return &ScalarBls12377{ + value: new(big.Int), + point: new(PointBls12377G1), + } +} + +func (p *PointBls12377G1) Neg() Point { + value := &bls12377.G1Affine{} + value.Neg(p.value) + return &PointBls12377G1{value} +} + +func (p *PointBls12377G1) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12377G1) + if ok { + value := &bls12377.G1Affine{} + return &PointBls12377G1{value.Add(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G1) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12377G1) + if ok { + value := &bls12377.G1Affine{} + return &PointBls12377G1{value.Sub(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G1) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarBls12377) + if ok { + value := &bls12377.G1Affine{} + return &PointBls12377G1{value.ScalarMultiplication(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G1) Equal(rhs Point) bool { + r, ok := rhs.(*PointBls12377G1) + if ok { + return p.value.Equal(r.value) + } else { + return false + } +} + +func (p *PointBls12377G1) Set(x, y *big.Int) (Point, error) { + if x.Cmp(core.Zero) == 0 && + y.Cmp(core.Zero) == 0 { + return p.Identity(), nil + } + var data [96]byte + x.FillBytes(data[:48]) + y.FillBytes(data[48:]) + value := &bls12377.G1Affine{} + _, err := value.SetBytes(data[:]) + if err != nil { + return nil, fmt.Errorf("invalid coordinates") + } + return &PointBls12377G1{value}, nil +} + +func (p *PointBls12377G1) ToAffineCompressed() []byte { + v := p.value.Bytes() + return v[:] +} + +func (p *PointBls12377G1) ToAffineUncompressed() []byte { + v := p.value.RawBytes() + return v[:] +} + +func (p *PointBls12377G1) FromAffineCompressed(bytes []byte) (Point, error) { + if len(bytes) != bls12377.SizeOfG1AffineCompressed { + return nil, fmt.Errorf("invalid point") + } + value := &bls12377.G1Affine{} + _, err := value.SetBytes(bytes) + if err != nil { + return nil, err + } + return &PointBls12377G1{value}, nil +} + +func (p *PointBls12377G1) FromAffineUncompressed(bytes []byte) (Point, error) { + if len(bytes) != bls12377.SizeOfG1AffineUncompressed { + return nil, fmt.Errorf("invalid point") + } + value := &bls12377.G1Affine{} + _, err := value.SetBytes(bytes) + if err != nil { + return nil, err + } + return &PointBls12377G1{value}, nil +} + +func (p *PointBls12377G1) CurveName() string { + return "BLS12377G1" +} + +func (p *PointBls12377G1) SumOfProducts(points []Point, scalars []Scalar) Point { + nScalars := make([]*big.Int, len(scalars)) + for i, sc := range scalars { + s, ok := sc.(*ScalarBls12377) + if !ok { + return nil + } + nScalars[i] = s.value + } + return sumOfProductsPippenger(points, nScalars) +} + +func (p *PointBls12377G1) OtherGroup() PairingPoint { + return new(PointBls12377G2).Identity().(PairingPoint) +} + +func (p *PointBls12377G1) Pairing(rhs PairingPoint) Scalar { + pt, ok := rhs.(*PointBls12377G2) + if !ok { + return nil + } + if !p.value.IsInSubGroup() || + !pt.value.IsInSubGroup() { + return nil + } + value := bls12377.GT{} + if p.value.IsInfinity() || pt.value.IsInfinity() { + return &ScalarBls12377Gt{&value} + } + value, err := bls12377.Pair([]bls12377.G1Affine{*p.value}, []bls12377.G2Affine{*pt.value}) + if err != nil { + return nil + } + + return &ScalarBls12377Gt{&value} +} + +func (p *PointBls12377G1) MultiPairing(points ...PairingPoint) Scalar { + return multiPairingBls12377(points...) +} + +func (p *PointBls12377G1) X() *big.Int { + b := p.value.RawBytes() + return new(big.Int).SetBytes(b[:48]) +} + +func (p *PointBls12377G1) Y() *big.Int { + b := p.value.RawBytes() + return new(big.Int).SetBytes(b[48:]) +} + +func (p *PointBls12377G1) Modulus() *big.Int { + return bls12377modulus +} + +func (p *PointBls12377G1) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointBls12377G1) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12377G1) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointBls12377G1) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointBls12377G1) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12377G1) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointBls12377G1) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointBls12377G1) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointBls12377G1) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} + +func (p *PointBls12377G2) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointBls12377G2) Hash(bytes []byte) Point { + var domain = []byte("BLS12377G2_XMD:SHA-256_SVDW_RO_") + pt, err := bls12377.HashToCurveG2Svdw(bytes, domain) + if err != nil { + return nil + } + return &PointBls12377G2{value: &pt} +} + +func (p *PointBls12377G2) Identity() Point { + t := bls12377.G2Affine{} + return &PointBls12377G2{ + value: t.Set(&g2Inf), + } +} + +func (p *PointBls12377G2) Generator() Point { + t := bls12377.G2Affine{} + _, _, _, g2Aff := bls12377.Generators() + return &PointBls12377G2{ + value: t.Set(&g2Aff), + } +} + +func (p *PointBls12377G2) IsIdentity() bool { + return p.value.IsInfinity() +} + +func (p *PointBls12377G2) IsNegative() bool { + // According to https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#serialization + // This bit represents the sign of the `y` coordinate which is what we want + return (p.value.Bytes()[0]>>5)&1 == 1 +} + +func (p *PointBls12377G2) IsOnCurve() bool { + return p.value.IsOnCurve() +} + +func (p *PointBls12377G2) Double() Point { + t := &bls12377.G2Jac{} + t.FromAffine(p.value) + t.DoubleAssign() + value := bls12377.G2Affine{} + return &PointBls12377G2{value.FromJacobian(t)} +} + +func (p *PointBls12377G2) Scalar() Scalar { + return &ScalarBls12377{ + value: new(big.Int), + point: new(PointBls12377G2), + } +} + +func (p *PointBls12377G2) Neg() Point { + value := &bls12377.G2Affine{} + value.Neg(p.value) + return &PointBls12377G2{value} +} + +func (p *PointBls12377G2) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12377G2) + if ok { + value := &bls12377.G2Affine{} + return &PointBls12377G2{value.Add(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G2) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12377G2) + if ok { + value := &bls12377.G2Affine{} + return &PointBls12377G2{value.Sub(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G2) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarBls12377) + if ok { + value := &bls12377.G2Affine{} + return &PointBls12377G2{value.ScalarMultiplication(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointBls12377G2) Equal(rhs Point) bool { + r, ok := rhs.(*PointBls12377G2) + if ok { + return p.value.Equal(r.value) + } else { + return false + } +} + +func (p *PointBls12377G2) Set(x, y *big.Int) (Point, error) { + if x.Cmp(core.Zero) == 0 && + y.Cmp(core.Zero) == 0 { + return p.Identity(), nil + } + var data [192]byte + x.FillBytes(data[:96]) + y.FillBytes(data[96:]) + value := &bls12377.G2Affine{} + _, err := value.SetBytes(data[:]) + if err != nil { + return nil, fmt.Errorf("invalid coordinates") + } + return &PointBls12377G2{value}, nil +} + +func (p *PointBls12377G2) ToAffineCompressed() []byte { + v := p.value.Bytes() + return v[:] +} + +func (p *PointBls12377G2) ToAffineUncompressed() []byte { + v := p.value.RawBytes() + return v[:] +} + +func (p *PointBls12377G2) FromAffineCompressed(bytes []byte) (Point, error) { + if len(bytes) != bls12377.SizeOfG2AffineCompressed { + return nil, fmt.Errorf("invalid point") + } + value := &bls12377.G2Affine{} + _, err := value.SetBytes(bytes) + if err != nil { + return nil, err + } + return &PointBls12377G2{value}, nil +} + +func (p *PointBls12377G2) FromAffineUncompressed(bytes []byte) (Point, error) { + if len(bytes) != bls12377.SizeOfG2AffineUncompressed { + return nil, fmt.Errorf("invalid point") + } + value := &bls12377.G2Affine{} + _, err := value.SetBytes(bytes) + if err != nil { + return nil, err + } + return &PointBls12377G2{value}, nil +} + +func (p *PointBls12377G2) CurveName() string { + return "BLS12377G2" +} + +func (p *PointBls12377G2) SumOfProducts(points []Point, scalars []Scalar) Point { + nScalars := make([]*big.Int, len(scalars)) + for i, sc := range scalars { + s, ok := sc.(*ScalarBls12377) + if !ok { + return nil + } + nScalars[i] = s.value + } + return sumOfProductsPippenger(points, nScalars) +} + +func (p *PointBls12377G2) OtherGroup() PairingPoint { + return new(PointBls12377G1).Identity().(PairingPoint) +} + +func (p *PointBls12377G2) Pairing(rhs PairingPoint) Scalar { + pt, ok := rhs.(*PointBls12377G1) + if !ok { + return nil + } + if !p.value.IsInSubGroup() || + !pt.value.IsInSubGroup() { + return nil + } + value := bls12377.GT{} + if p.value.IsInfinity() || pt.value.IsInfinity() { + return &ScalarBls12377Gt{&value} + } + value, err := bls12377.Pair([]bls12377.G1Affine{*pt.value}, []bls12377.G2Affine{*p.value}) + if err != nil { + return nil + } + + return &ScalarBls12377Gt{&value} +} + +func (p *PointBls12377G2) MultiPairing(points ...PairingPoint) Scalar { + return multiPairingBls12377(points...) +} + +func (p *PointBls12377G2) X() *big.Int { + b := p.value.RawBytes() + return new(big.Int).SetBytes(b[:96]) +} + +func (p *PointBls12377G2) Y() *big.Int { + b := p.value.RawBytes() + return new(big.Int).SetBytes(b[96:]) +} + +func (p *PointBls12377G2) Modulus() *big.Int { + return bls12377modulus +} + +func (p *PointBls12377G2) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointBls12377G2) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12377G2) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointBls12377G2) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointBls12377G2) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12377G2) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointBls12377G2) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointBls12377G2) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointBls12377G2) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} + +func multiPairingBls12377(points ...PairingPoint) Scalar { + if len(points)%2 != 0 { + return nil + } + g1Arr := make([]bls12377.G1Affine, 0, len(points)/2) + g2Arr := make([]bls12377.G2Affine, 0, len(points)/2) + valid := true + for i := 0; i < len(points); i += 2 { + pt1, ok := points[i].(*PointBls12377G1) + valid = valid && ok + pt2, ok := points[i+1].(*PointBls12377G2) + valid = valid && ok + if valid { + valid = valid && pt1.value.IsInSubGroup() + valid = valid && pt2.value.IsInSubGroup() + } + if valid { + g1Arr = append(g1Arr, *pt1.value) + g2Arr = append(g2Arr, *pt2.value) + } + } + if !valid { + return nil + } + + value, err := bls12377.Pair(g1Arr, g2Arr) + if err != nil { + return nil + } + + return &ScalarBls12377Gt{&value} +} + +func (s *ScalarBls12377Gt) Random(reader io.Reader) Scalar { + const width = 48 + offset := 0 + var data [bls12377.SizeOfGT]byte + for i := 0; i < 12; i++ { + tv, err := rand.Int(reader, bls12377modulus) + if err != nil { + return nil + } + tv.FillBytes(data[offset*width : (offset+1)*width]) + offset++ + } + value := bls12377.GT{} + err := value.SetBytes(data[:]) + if err != nil { + return nil + } + return &ScalarBls12377Gt{&value} +} + +func (s *ScalarBls12377Gt) Hash(bytes []byte) Scalar { + reader := sha3.NewShake256() + n, err := reader.Write(bytes) + if err != nil { + return nil + } + if n != len(bytes) { + return nil + } + return s.Random(reader) +} + +func (s *ScalarBls12377Gt) Zero() Scalar { + var t [bls12377.SizeOfGT]byte + value := bls12377.GT{} + err := value.SetBytes(t[:]) + if err != nil { + return nil + } + return &ScalarBls12377Gt{&value} +} + +func (s *ScalarBls12377Gt) One() Scalar { + value := bls12377.GT{} + return &ScalarBls12377Gt{value.SetOne()} +} + +func (s *ScalarBls12377Gt) IsZero() bool { + r := byte(0) + b := s.value.Bytes() + for _, i := range b { + r |= i + } + return r == 0 +} + +func (s *ScalarBls12377Gt) IsOne() bool { + o := bls12377.GT{} + return s.value.Equal(o.SetOne()) +} + +func (s *ScalarBls12377Gt) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarBls12377Gt) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12377Gt) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarBls12377Gt) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarBls12377Gt) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12377Gt) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarBls12377Gt) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarBls12377Gt) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarBls12377Gt) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +func (s *ScalarBls12377Gt) IsOdd() bool { + data := s.value.Bytes() + return data[len(data)-1]&1 == 1 +} + +func (s *ScalarBls12377Gt) IsEven() bool { + data := s.value.Bytes() + return data[len(data)-1]&1 == 0 +} + +func (s *ScalarBls12377Gt) New(input int) Scalar { + var data [576]byte + data[3] = byte(input >> 24 & 0xFF) + data[2] = byte(input >> 16 & 0xFF) + data[1] = byte(input >> 8 & 0xFF) + data[0] = byte(input & 0xFF) + + value := bls12377.GT{} + err := value.SetBytes(data[:]) + if err != nil { + return nil + } + return &ScalarBls12377Gt{&value} +} + +func (s *ScalarBls12377Gt) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarBls12377Gt) + if ok && s.value.Equal(r.value) { + return 0 + } else { + return -2 + } +} + +func (s *ScalarBls12377Gt) Square() Scalar { + value := bls12377.GT{} + return &ScalarBls12377Gt{ + value.Square(s.value), + } +} + +func (s *ScalarBls12377Gt) Double() Scalar { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Add(s.value, s.value), + } +} + +func (s *ScalarBls12377Gt) Invert() (Scalar, error) { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Inverse(s.value), + }, nil +} + +func (s *ScalarBls12377Gt) Sqrt() (Scalar, error) { + // Not implemented + return nil, nil +} + +func (s *ScalarBls12377Gt) Cube() Scalar { + value := &bls12377.GT{} + value.Square(s.value) + value.Mul(value, s.value) + return &ScalarBls12377Gt{ + value, + } +} + +func (s *ScalarBls12377Gt) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377Gt) + if ok { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Add(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarBls12377Gt) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377Gt) + if ok { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Sub(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarBls12377Gt) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377Gt) + if ok { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Mul(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarBls12377Gt) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarBls12377Gt) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12377Gt) + if ok { + value := &bls12377.GT{} + value.Inverse(r.value) + value.Mul(value, s.value) + return &ScalarBls12377Gt{ + value, + } + } else { + return nil + } +} + +func (s *ScalarBls12377Gt) Neg() Scalar { + sValue := &bls12377.GT{} + sValue.SetOne() + value := &bls12377.GT{} + value.SetOne() + value.Sub(value, sValue) + return &ScalarBls12377Gt{ + value.Sub(value, s.value), + } +} + +func (s *ScalarBls12377Gt) SetBigInt(v *big.Int) (Scalar, error) { + var bytes [576]byte + v.FillBytes(bytes[:]) + return s.SetBytes(bytes[:]) +} + +func (s *ScalarBls12377Gt) BigInt() *big.Int { + b := s.value.Bytes() + return new(big.Int).SetBytes(b[:]) +} + +func (s *ScalarBls12377Gt) Point() Point { + p := &PointBls12377G1{} + return p.Identity() +} + +func (s *ScalarBls12377Gt) Bytes() []byte { + b := s.value.Bytes() + return b[:] +} + +func (s *ScalarBls12377Gt) SetBytes(bytes []byte) (Scalar, error) { + value := &bls12377.GT{} + err := value.SetBytes(bytes) + if err != nil { + return nil, err + } + return &ScalarBls12377Gt{value}, nil +} + +func (s *ScalarBls12377Gt) SetBytesWide(bytes []byte) (Scalar, error) { + l := len(bytes) + if l != 1152 { + return nil, fmt.Errorf("invalid byte sequence") + } + value := &bls12377.GT{} + err := value.SetBytes(bytes[:l/2]) + if err != nil { + return nil, err + } + value2 := &bls12377.GT{} + err = value2.SetBytes(bytes[l/2:]) + if err != nil { + return nil, err + } + value.Add(value, value2) + return &ScalarBls12377Gt{value}, nil +} + +func (s *ScalarBls12377Gt) Clone() Scalar { + value := &bls12377.GT{} + return &ScalarBls12377Gt{ + value.Set(s.value), + } +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12381_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12381_curve.go new file mode 100644 index 0000000000..a53a3fa9b1 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/bls12381_curve.go @@ -0,0 +1,1129 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "fmt" + "io" + "math/big" + + "golang.org/x/crypto/sha3" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" +) + +var bls12381modulus = bhex("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab") + +type ScalarBls12381 struct { + Value *native.Field + point Point +} + +type PointBls12381G1 struct { + Value *bls12381.G1 +} + +type PointBls12381G2 struct { + Value *bls12381.G2 +} + +type ScalarBls12381Gt struct { + Value *bls12381.Gt +} + +func (s *ScalarBls12381) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarBls12381) Hash(bytes []byte) Scalar { + dst := []byte("BLS12381_XMD:SHA-256_SSWU_RO_") + xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), bytes, dst, 48) + var t [64]byte + copy(t[:48], internal.ReverseScalarBytes(xmd)) + + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().SetBytesWide(&t), + point: s.point, + } +} + +func (s *ScalarBls12381) Zero() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().SetZero(), + point: s.point, + } +} + +func (s *ScalarBls12381) One() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().SetOne(), + point: s.point, + } +} + +func (s *ScalarBls12381) IsZero() bool { + return s.Value.IsZero() == 1 +} + +func (s *ScalarBls12381) IsOne() bool { + return s.Value.IsOne() == 1 +} + +func (s *ScalarBls12381) IsOdd() bool { + bytes := s.Value.Bytes() + return bytes[0]&1 == 1 +} + +func (s *ScalarBls12381) IsEven() bool { + bytes := s.Value.Bytes() + return bytes[0]&1 == 0 +} + +func (s *ScalarBls12381) New(value int) Scalar { + t := bls12381.Bls12381FqNew() + v := big.NewInt(int64(value)) + if value < 0 { + v.Mod(v, t.Params.BiModulus) + } + return &ScalarBls12381{ + Value: t.SetBigInt(v), + point: s.point, + } +} + +func (s *ScalarBls12381) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarBls12381) + if ok { + return s.Value.Cmp(r.Value) + } else { + return -2 + } +} + +func (s *ScalarBls12381) Square() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Square(s.Value), + point: s.point, + } +} + +func (s *ScalarBls12381) Double() Scalar { + v := bls12381.Bls12381FqNew().Double(s.Value) + return &ScalarBls12381{ + Value: v, + point: s.point, + } +} + +func (s *ScalarBls12381) Invert() (Scalar, error) { + value, wasInverted := bls12381.Bls12381FqNew().Invert(s.Value) + if !wasInverted { + return nil, fmt.Errorf("inverse doesn't exist") + } + return &ScalarBls12381{ + Value: value, + point: s.point, + }, nil +} + +func (s *ScalarBls12381) Sqrt() (Scalar, error) { + value, wasSquare := bls12381.Bls12381FqNew().Sqrt(s.Value) + if !wasSquare { + return nil, fmt.Errorf("not a square") + } + return &ScalarBls12381{ + Value: value, + point: s.point, + }, nil +} + +func (s *ScalarBls12381) Cube() Scalar { + value := bls12381.Bls12381FqNew().Square(s.Value) + value.Mul(value, s.Value) + return &ScalarBls12381{ + Value: value, + point: s.point, + } +} + +func (s *ScalarBls12381) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381) + if ok { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Add(s.Value, r.Value), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12381) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381) + if ok { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Sub(s.Value, r.Value), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12381) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381) + if ok { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Mul(s.Value, r.Value), + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12381) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarBls12381) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381) + if ok { + v, wasInverted := bls12381.Bls12381FqNew().Invert(r.Value) + if !wasInverted { + return nil + } + v.Mul(v, s.Value) + return &ScalarBls12381{ + Value: v, + point: s.point, + } + } else { + return nil + } +} + +func (s *ScalarBls12381) Neg() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Neg(s.Value), + point: s.point, + } +} + +func (s *ScalarBls12381) SetBigInt(v *big.Int) (Scalar, error) { + if v == nil { + return nil, fmt.Errorf("invalid value") + } + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().SetBigInt(v), + point: s.point, + }, nil +} + +func (s *ScalarBls12381) BigInt() *big.Int { + return s.Value.BigInt() +} + +func (s *ScalarBls12381) Bytes() []byte { + t := s.Value.Bytes() + return internal.ReverseScalarBytes(t[:]) +} + +func (s *ScalarBls12381) SetBytes(bytes []byte) (Scalar, error) { + if len(bytes) != 32 { + return nil, fmt.Errorf("invalid length") + } + var seq [32]byte + copy(seq[:], internal.ReverseScalarBytes(bytes)) + value, err := bls12381.Bls12381FqNew().SetBytes(&seq) + if err != nil { + return nil, err + } + return &ScalarBls12381{ + value, s.point, + }, nil +} + +func (s *ScalarBls12381) SetBytesWide(bytes []byte) (Scalar, error) { + if len(bytes) != 64 { + return nil, fmt.Errorf("invalid length") + } + var seq [64]byte + copy(seq[:], bytes) + return &ScalarBls12381{ + bls12381.Bls12381FqNew().SetBytesWide(&seq), s.point, + }, nil +} + +func (s *ScalarBls12381) Point() Point { + return s.point.Identity() +} + +func (s *ScalarBls12381) Clone() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Set(s.Value), + point: s.point, + } +} + +func (s *ScalarBls12381) SetPoint(p Point) PairingScalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew().Set(s.Value), + point: p, + } +} + +func (s *ScalarBls12381) Order() *big.Int { + return s.Value.Params.BiModulus +} + +func (s *ScalarBls12381) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarBls12381) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12381) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.Value = ss.Value + s.point = ss.point + return nil +} + +func (s *ScalarBls12381) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarBls12381) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12381) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.Value = ss.Value + s.point = ss.point + return nil +} + +func (s *ScalarBls12381) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarBls12381) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarBls12381) + if !ok { + return fmt.Errorf("invalid type") + } + s.Value = S.Value + return nil +} + +func (p *PointBls12381G1) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointBls12381G1) Hash(bytes []byte) Point { + var domain = []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_") + pt := new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), bytes, domain) + return &PointBls12381G1{Value: pt} +} + +func (p *PointBls12381G1) Identity() Point { + return &PointBls12381G1{ + Value: new(bls12381.G1).Identity(), + } +} + +func (p *PointBls12381G1) Generator() Point { + return &PointBls12381G1{ + Value: new(bls12381.G1).Generator(), + } +} + +func (p *PointBls12381G1) IsIdentity() bool { + return p.Value.IsIdentity() == 1 +} + +func (p *PointBls12381G1) IsNegative() bool { + // According to https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#serialization + // This bit represents the sign of the `y` coordinate which is what we want + return (p.Value.ToCompressed()[0]>>5)&1 == 1 +} + +func (p *PointBls12381G1) IsOnCurve() bool { + return p.Value.IsOnCurve() == 1 +} + +func (p *PointBls12381G1) Double() Point { + return &PointBls12381G1{new(bls12381.G1).Double(p.Value)} +} + +func (p *PointBls12381G1) Scalar() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew(), + point: new(PointBls12381G1), + } +} + +func (p *PointBls12381G1) Neg() Point { + return &PointBls12381G1{new(bls12381.G1).Neg(p.Value)} +} + +func (p *PointBls12381G1) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12381G1) + if ok { + return &PointBls12381G1{new(bls12381.G1).Add(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G1) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12381G1) + if ok { + return &PointBls12381G1{new(bls12381.G1).Sub(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G1) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarBls12381) + if ok { + return &PointBls12381G1{new(bls12381.G1).Mul(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G1) Equal(rhs Point) bool { + r, ok := rhs.(*PointBls12381G1) + if ok { + return p.Value.Equal(r.Value) == 1 + } else { + return false + } +} + +func (p *PointBls12381G1) Set(x, y *big.Int) (Point, error) { + value, err := new(bls12381.G1).SetBigInt(x, y) + if err != nil { + return nil, fmt.Errorf("invalid coordinates") + } + return &PointBls12381G1{value}, nil +} + +func (p *PointBls12381G1) ToAffineCompressed() []byte { + out := p.Value.ToCompressed() + return out[:] +} + +func (p *PointBls12381G1) ToAffineUncompressed() []byte { + out := p.Value.ToUncompressed() + return out[:] +} + +func (p *PointBls12381G1) FromAffineCompressed(bytes []byte) (Point, error) { + var b [bls12381.FieldBytes]byte + copy(b[:], bytes) + value, err := new(bls12381.G1).FromCompressed(&b) + if err != nil { + return nil, err + } + return &PointBls12381G1{value}, nil +} + +func (p *PointBls12381G1) FromAffineUncompressed(bytes []byte) (Point, error) { + var b [96]byte + copy(b[:], bytes) + value, err := new(bls12381.G1).FromUncompressed(&b) + if err != nil { + return nil, err + } + return &PointBls12381G1{value}, nil +} + +func (p *PointBls12381G1) CurveName() string { + return "BLS12381G1" +} + +func (p *PointBls12381G1) SumOfProducts(points []Point, scalars []Scalar) Point { + nPoints := make([]*bls12381.G1, len(points)) + nScalars := make([]*native.Field, len(scalars)) + for i, pt := range points { + pp, ok := pt.(*PointBls12381G1) + if !ok { + return nil + } + nPoints[i] = pp.Value + } + for i, sc := range scalars { + s, ok := sc.(*ScalarBls12381) + if !ok { + return nil + } + nScalars[i] = s.Value + } + value, err := new(bls12381.G1).SumOfProducts(nPoints, nScalars) + if err != nil { + return nil + } + return &PointBls12381G1{value} +} + +func (p *PointBls12381G1) OtherGroup() PairingPoint { + return new(PointBls12381G2).Identity().(PairingPoint) +} + +func (p *PointBls12381G1) Pairing(rhs PairingPoint) Scalar { + pt, ok := rhs.(*PointBls12381G2) + if !ok { + return nil + } + e := new(bls12381.Engine) + e.AddPair(p.Value, pt.Value) + + value := e.Result() + + return &ScalarBls12381Gt{value} +} + +func (p *PointBls12381G1) MultiPairing(points ...PairingPoint) Scalar { + return multiPairing(points...) +} + +func (p *PointBls12381G1) X() *big.Int { + return p.Value.GetX().BigInt() +} + +func (p *PointBls12381G1) Y() *big.Int { + return p.Value.GetY().BigInt() +} + +func (p *PointBls12381G1) Modulus() *big.Int { + return bls12381modulus +} + +func (p *PointBls12381G1) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointBls12381G1) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12381G1) + if !ok { + return fmt.Errorf("invalid point") + } + p.Value = ppt.Value + return nil +} + +func (p *PointBls12381G1) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointBls12381G1) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12381G1) + if !ok { + return fmt.Errorf("invalid point") + } + p.Value = ppt.Value + return nil +} + +func (p *PointBls12381G1) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointBls12381G1) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointBls12381G1) + if !ok { + return fmt.Errorf("invalid type") + } + p.Value = P.Value + return nil +} + +func (p *PointBls12381G2) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointBls12381G2) Hash(bytes []byte) Point { + var domain = []byte("BLS12381G2_XMD:SHA-256_SSWU_RO_") + pt := new(bls12381.G2).Hash(native.EllipticPointHasherSha256(), bytes, domain) + return &PointBls12381G2{Value: pt} +} + +func (p *PointBls12381G2) Identity() Point { + return &PointBls12381G2{ + Value: new(bls12381.G2).Identity(), + } +} + +func (p *PointBls12381G2) Generator() Point { + return &PointBls12381G2{ + Value: new(bls12381.G2).Generator(), + } +} + +func (p *PointBls12381G2) IsIdentity() bool { + return p.Value.IsIdentity() == 1 +} + +func (p *PointBls12381G2) IsNegative() bool { + // According to https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#serialization + // This bit represents the sign of the `y` coordinate which is what we want + return (p.Value.ToCompressed()[0]>>5)&1 == 1 +} + +func (p *PointBls12381G2) IsOnCurve() bool { + return p.Value.IsOnCurve() == 1 +} + +func (p *PointBls12381G2) Double() Point { + return &PointBls12381G2{new(bls12381.G2).Double(p.Value)} +} + +func (p *PointBls12381G2) Scalar() Scalar { + return &ScalarBls12381{ + Value: bls12381.Bls12381FqNew(), + point: new(PointBls12381G2), + } +} + +func (p *PointBls12381G2) Neg() Point { + return &PointBls12381G2{new(bls12381.G2).Neg(p.Value)} +} + +func (p *PointBls12381G2) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12381G2) + if ok { + return &PointBls12381G2{new(bls12381.G2).Add(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G2) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointBls12381G2) + if ok { + return &PointBls12381G2{new(bls12381.G2).Sub(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G2) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarBls12381) + if ok { + return &PointBls12381G2{new(bls12381.G2).Mul(p.Value, r.Value)} + } else { + return nil + } +} + +func (p *PointBls12381G2) Equal(rhs Point) bool { + r, ok := rhs.(*PointBls12381G2) + if ok { + return p.Value.Equal(r.Value) == 1 + } else { + return false + } +} + +func (p *PointBls12381G2) Set(x, y *big.Int) (Point, error) { + value, err := new(bls12381.G2).SetBigInt(x, y) + if err != nil { + return nil, fmt.Errorf("invalid coordinates") + } + return &PointBls12381G2{value}, nil +} + +func (p *PointBls12381G2) ToAffineCompressed() []byte { + out := p.Value.ToCompressed() + return out[:] +} + +func (p *PointBls12381G2) ToAffineUncompressed() []byte { + out := p.Value.ToUncompressed() + return out[:] +} + +func (p *PointBls12381G2) FromAffineCompressed(bytes []byte) (Point, error) { + var b [bls12381.WideFieldBytes]byte + copy(b[:], bytes) + value, err := new(bls12381.G2).FromCompressed(&b) + if err != nil { + return nil, err + } + return &PointBls12381G2{value}, nil +} + +func (p *PointBls12381G2) FromAffineUncompressed(bytes []byte) (Point, error) { + var b [bls12381.DoubleWideFieldBytes]byte + copy(b[:], bytes) + value, err := new(bls12381.G2).FromUncompressed(&b) + if err != nil { + return nil, err + } + return &PointBls12381G2{value}, nil +} + +func (p *PointBls12381G2) CurveName() string { + return "BLS12381G2" +} + +func (p *PointBls12381G2) SumOfProducts(points []Point, scalars []Scalar) Point { + nPoints := make([]*bls12381.G2, len(points)) + nScalars := make([]*native.Field, len(scalars)) + for i, pt := range points { + pp, ok := pt.(*PointBls12381G2) + if !ok { + return nil + } + nPoints[i] = pp.Value + } + for i, sc := range scalars { + s, ok := sc.(*ScalarBls12381) + if !ok { + return nil + } + nScalars[i] = s.Value + } + value, err := new(bls12381.G2).SumOfProducts(nPoints, nScalars) + if err != nil { + return nil + } + return &PointBls12381G2{value} +} + +func (p *PointBls12381G2) OtherGroup() PairingPoint { + return new(PointBls12381G1).Identity().(PairingPoint) +} + +func (p *PointBls12381G2) Pairing(rhs PairingPoint) Scalar { + pt, ok := rhs.(*PointBls12381G1) + if !ok { + return nil + } + e := new(bls12381.Engine) + e.AddPair(pt.Value, p.Value) + + value := e.Result() + + return &ScalarBls12381Gt{value} +} + +func (p *PointBls12381G2) MultiPairing(points ...PairingPoint) Scalar { + return multiPairing(points...) +} + +func (p *PointBls12381G2) X() *big.Int { + x := p.Value.ToUncompressed() + return new(big.Int).SetBytes(x[:bls12381.WideFieldBytes]) +} + +func (p *PointBls12381G2) Y() *big.Int { + y := p.Value.ToUncompressed() + return new(big.Int).SetBytes(y[bls12381.WideFieldBytes:]) +} + +func (p *PointBls12381G2) Modulus() *big.Int { + return bls12381modulus +} + +func (p *PointBls12381G2) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointBls12381G2) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12381G2) + if !ok { + return fmt.Errorf("invalid point") + } + p.Value = ppt.Value + return nil +} + +func (p *PointBls12381G2) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointBls12381G2) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointBls12381G2) + if !ok { + return fmt.Errorf("invalid point") + } + p.Value = ppt.Value + return nil +} + +func (p *PointBls12381G2) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointBls12381G2) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointBls12381G2) + if !ok { + return fmt.Errorf("invalid type") + } + p.Value = P.Value + return nil +} + +func multiPairing(points ...PairingPoint) Scalar { + if len(points)%2 != 0 { + return nil + } + valid := true + eng := new(bls12381.Engine) + for i := 0; i < len(points); i += 2 { + pt1, ok := points[i].(*PointBls12381G1) + valid = valid && ok + pt2, ok := points[i+1].(*PointBls12381G2) + valid = valid && ok + if valid { + eng.AddPair(pt1.Value, pt2.Value) + } + } + if !valid { + return nil + } + + value := eng.Result() + return &ScalarBls12381Gt{value} +} + +func (s *ScalarBls12381Gt) Random(reader io.Reader) Scalar { + value, err := new(bls12381.Gt).Random(reader) + if err != nil { + return nil + } + return &ScalarBls12381Gt{value} +} + +func (s *ScalarBls12381Gt) Hash(bytes []byte) Scalar { + reader := sha3.NewShake256() + n, err := reader.Write(bytes) + if err != nil { + return nil + } + if n != len(bytes) { + return nil + } + return s.Random(reader) +} + +func (s *ScalarBls12381Gt) Zero() Scalar { + return &ScalarBls12381Gt{new(bls12381.Gt)} +} + +func (s *ScalarBls12381Gt) One() Scalar { + return &ScalarBls12381Gt{new(bls12381.Gt).SetOne()} +} + +func (s *ScalarBls12381Gt) IsZero() bool { + return s.Value.IsZero() == 1 +} + +func (s *ScalarBls12381Gt) IsOne() bool { + return s.Value.IsOne() == 1 +} + +func (s *ScalarBls12381Gt) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarBls12381Gt) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12381Gt) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.Value = ss.Value + return nil +} + +func (s *ScalarBls12381Gt) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarBls12381Gt) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarBls12381Gt) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.Value = ss.Value + return nil +} + +func (s *ScalarBls12381Gt) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarBls12381Gt) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarBls12381Gt) + if !ok { + return fmt.Errorf("invalid type") + } + s.Value = S.Value + return nil +} + +func (s *ScalarBls12381Gt) IsOdd() bool { + data := s.Value.Bytes() + return data[0]&1 == 1 +} + +func (s *ScalarBls12381Gt) IsEven() bool { + data := s.Value.Bytes() + return data[0]&1 == 0 +} + +func (s *ScalarBls12381Gt) New(input int) Scalar { + var data [bls12381.GtFieldBytes]byte + data[3] = byte(input >> 24 & 0xFF) + data[2] = byte(input >> 16 & 0xFF) + data[1] = byte(input >> 8 & 0xFF) + data[0] = byte(input & 0xFF) + + value, isCanonical := new(bls12381.Gt).SetBytes(&data) + if isCanonical != 1 { + return nil + } + return &ScalarBls12381Gt{value} +} + +func (s *ScalarBls12381Gt) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarBls12381Gt) + if ok && s.Value.Equal(r.Value) == 1 { + return 0 + } else { + return -2 + } +} + +func (s *ScalarBls12381Gt) Square() Scalar { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Square(s.Value), + } +} + +func (s *ScalarBls12381Gt) Double() Scalar { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Double(s.Value), + } +} + +func (s *ScalarBls12381Gt) Invert() (Scalar, error) { + value, wasInverted := new(bls12381.Gt).Invert(s.Value) + if wasInverted != 1 { + return nil, fmt.Errorf("not invertible") + } + return &ScalarBls12381Gt{ + value, + }, nil +} + +func (s *ScalarBls12381Gt) Sqrt() (Scalar, error) { + // Not implemented + return nil, nil +} + +func (s *ScalarBls12381Gt) Cube() Scalar { + value := new(bls12381.Gt).Square(s.Value) + value.Add(value, s.Value) + return &ScalarBls12381Gt{ + value, + } +} + +func (s *ScalarBls12381Gt) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381Gt) + if ok { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Add(s.Value, r.Value), + } + } else { + return nil + } +} + +func (s *ScalarBls12381Gt) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381Gt) + if ok { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Sub(s.Value, r.Value), + } + } else { + return nil + } +} + +func (s *ScalarBls12381Gt) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381Gt) + if ok { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Add(s.Value, r.Value), + } + } else { + return nil + } +} + +func (s *ScalarBls12381Gt) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarBls12381Gt) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarBls12381Gt) + if ok { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Sub(s.Value, r.Value), + } + } else { + return nil + } +} + +func (s *ScalarBls12381Gt) Neg() Scalar { + return &ScalarBls12381Gt{ + new(bls12381.Gt).Neg(s.Value), + } +} + +func (s *ScalarBls12381Gt) SetBigInt(v *big.Int) (Scalar, error) { + var bytes [bls12381.GtFieldBytes]byte + v.FillBytes(bytes[:]) + return s.SetBytes(bytes[:]) +} + +func (s *ScalarBls12381Gt) BigInt() *big.Int { + bytes := s.Value.Bytes() + return new(big.Int).SetBytes(bytes[:]) +} + +func (s *ScalarBls12381Gt) Point() Point { + return &PointBls12381G1{Value: new(bls12381.G1).Identity()} +} + +func (s *ScalarBls12381Gt) Bytes() []byte { + bytes := s.Value.Bytes() + return bytes[:] +} + +func (s *ScalarBls12381Gt) SetBytes(bytes []byte) (Scalar, error) { + var b [bls12381.GtFieldBytes]byte + copy(b[:], bytes) + ss, isCanonical := new(bls12381.Gt).SetBytes(&b) + if isCanonical == 0 { + return nil, fmt.Errorf("invalid bytes") + } + return &ScalarBls12381Gt{ss}, nil +} + +func (s *ScalarBls12381Gt) SetBytesWide(bytes []byte) (Scalar, error) { + l := len(bytes) + if l != bls12381.GtFieldBytes*2 { + return nil, fmt.Errorf("invalid byte sequence") + } + var b [bls12381.GtFieldBytes]byte + copy(b[:], bytes[:bls12381.GtFieldBytes]) + + value, isCanonical := new(bls12381.Gt).SetBytes(&b) + if isCanonical == 0 { + return nil, fmt.Errorf("invalid byte sequence") + } + copy(b[:], bytes[bls12381.GtFieldBytes:]) + value2, isCanonical := new(bls12381.Gt).SetBytes(&b) + if isCanonical == 0 { + return nil, fmt.Errorf("invalid byte sequence") + } + value.Add(value, value2) + return &ScalarBls12381Gt{value}, nil +} + +func (s *ScalarBls12381Gt) Clone() Scalar { + return &ScalarBls12381Gt{ + Value: new(bls12381.Gt).Set(s.Value), + } +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/curve.go new file mode 100644 index 0000000000..d53531b4ad --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/curve.go @@ -0,0 +1,861 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + "encoding/hex" + "encoding/json" + "fmt" + "hash" + "io" + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" +) + +var ( + k256Initonce sync.Once + k256 Curve + + bls12381g1Initonce sync.Once + bls12381g1 Curve + + bls12381g2Initonce sync.Once + bls12381g2 Curve + + bls12377g1Initonce sync.Once + bls12377g1 Curve + + bls12377g2Initonce sync.Once + bls12377g2 Curve + + p256Initonce sync.Once + p256 Curve + + ed25519Initonce sync.Once + ed25519 Curve + + pallasInitonce sync.Once + pallas Curve +) + +const ( + K256Name = "secp256k1" + BLS12381G1Name = "BLS12381G1" + BLS12381G2Name = "BLS12381G2" + BLS12831Name = "BLS12831" + P256Name = "P-256" + ED25519Name = "ed25519" + PallasName = "pallas" + BLS12377G1Name = "BLS12377G1" + BLS12377G2Name = "BLS12377G2" + BLS12377Name = "BLS12377" +) + +const scalarBytes = 32 + +// Scalar represents an element of the scalar field \mathbb{F}_q +// of the elliptic curve construction. +type Scalar interface { + // Random returns a random scalar using the provided reader + // to retrieve bytes + Random(reader io.Reader) Scalar + // Hash the specific bytes in a manner to yield a + // uniformly distributed scalar + Hash(bytes []byte) Scalar + // Zero returns the additive identity element + Zero() Scalar + // One returns the multiplicative identity element + One() Scalar + // IsZero returns true if this element is the additive identity element + IsZero() bool + // IsOne returns true if this element is the multiplicative identity element + IsOne() bool + // IsOdd returns true if this element is odd + IsOdd() bool + // IsEven returns true if this element is even + IsEven() bool + // New returns an element with the value equal to `value` + New(value int) Scalar + // Cmp returns + // -2 if this element is in a different field than rhs + // -1 if this element is less than rhs + // 0 if this element is equal to rhs + // 1 if this element is greater than rhs + Cmp(rhs Scalar) int + // Square returns element*element + Square() Scalar + // Double returns element+element + Double() Scalar + // Invert returns element^-1 mod p + Invert() (Scalar, error) + // Sqrt computes the square root of this element if it exists. + Sqrt() (Scalar, error) + // Cube returns element*element*element + Cube() Scalar + // Add returns element+rhs + Add(rhs Scalar) Scalar + // Sub returns element-rhs + Sub(rhs Scalar) Scalar + // Mul returns element*rhs + Mul(rhs Scalar) Scalar + // MulAdd returns element * y + z mod p + MulAdd(y, z Scalar) Scalar + // Div returns element*rhs^-1 mod p + Div(rhs Scalar) Scalar + // Neg returns -element mod p + Neg() Scalar + // SetBigInt returns this element set to the value of v + SetBigInt(v *big.Int) (Scalar, error) + // BigInt returns this element as a big integer + BigInt() *big.Int + // Point returns the associated point for this scalar + Point() Point + // Bytes returns the canonical byte representation of this scalar + Bytes() []byte + // SetBytes creates a scalar from the canonical representation expecting the exact number of bytes needed to represent the scalar + SetBytes(bytes []byte) (Scalar, error) + // SetBytesWide creates a scalar expecting double the exact number of bytes needed to represent the scalar which is reduced by the modulus + SetBytesWide(bytes []byte) (Scalar, error) + // Clone returns a cloned Scalar of this value + Clone() Scalar +} + +type PairingScalar interface { + Scalar + SetPoint(p Point) PairingScalar +} + +func unmarshalScalar(input []byte) (*Curve, []byte, error) { + sep := byte(':') + i := 0 + for ; i < len(input); i++ { + if input[i] == sep { + break + } + } + name := string(input[:i]) + curve := GetCurveByName(name) + if curve == nil { + return nil, nil, fmt.Errorf("unrecognized curve") + } + return curve, input[i+1:], nil +} + +func scalarMarshalBinary(scalar Scalar) ([]byte, error) { + // All scalars are 32 bytes long + // The last 32 bytes are the actual value + // The first remaining bytes are the curve name + // separated by a colon + name := []byte(scalar.Point().CurveName()) + output := make([]byte, len(name)+1+scalarBytes) + copy(output[:len(name)], name) + output[len(name)] = byte(':') + copy(output[len(name)+1:], scalar.Bytes()) + return output, nil +} + +func scalarUnmarshalBinary(input []byte) (Scalar, error) { + // All scalars are 32 bytes long + // The first 32 bytes are the actual value + // The remaining bytes are the curve name + if len(input) < scalarBytes+1+len(P256Name) { + return nil, fmt.Errorf("invalid byte sequence") + } + sc, data, err := unmarshalScalar(input) + if err != nil { + return nil, err + } + return sc.Scalar.SetBytes(data) +} + +func scalarMarshalText(scalar Scalar) ([]byte, error) { + // All scalars are 32 bytes long + // For text encoding we put the curve name first for readability + // separated by a colon, then the hex encoding of the scalar + // which avoids the base64 weakness with strict mode or not + name := []byte(scalar.Point().CurveName()) + output := make([]byte, len(name)+1+scalarBytes*2) + copy(output[:len(name)], name) + output[len(name)] = byte(':') + _ = hex.Encode(output[len(name)+1:], scalar.Bytes()) + return output, nil +} + +func scalarUnmarshalText(input []byte) (Scalar, error) { + if len(input) < scalarBytes*2+len(P256Name)+1 { + return nil, fmt.Errorf("invalid byte sequence") + } + curve, data, err := unmarshalScalar(input) + if err != nil { + return nil, err + } + var t [scalarBytes]byte + _, err = hex.Decode(t[:], data) + if err != nil { + return nil, err + } + return curve.Scalar.SetBytes(t[:]) +} + +func scalarMarshalJson(scalar Scalar) ([]byte, error) { + m := make(map[string]string, 2) + m["type"] = scalar.Point().CurveName() + m["value"] = hex.EncodeToString(scalar.Bytes()) + return json.Marshal(m) +} + +func scalarUnmarshalJson(input []byte) (Scalar, error) { + var m map[string]string + + err := json.Unmarshal(input, &m) + if err != nil { + return nil, err + } + curve := GetCurveByName(m["type"]) + if curve == nil { + return nil, fmt.Errorf("invalid type") + } + s, err := hex.DecodeString(m["value"]) + if err != nil { + return nil, err + } + S, err := curve.Scalar.SetBytes(s) + if err != nil { + return nil, err + } + return S, nil +} + +// Point represents an elliptic curve point +type Point interface { + Random(reader io.Reader) Point + Hash(bytes []byte) Point + Identity() Point + Generator() Point + IsIdentity() bool + IsNegative() bool + IsOnCurve() bool + Double() Point + Scalar() Scalar + Neg() Point + Add(rhs Point) Point + Sub(rhs Point) Point + Mul(rhs Scalar) Point + Equal(rhs Point) bool + Set(x, y *big.Int) (Point, error) + ToAffineCompressed() []byte + ToAffineUncompressed() []byte + FromAffineCompressed(bytes []byte) (Point, error) + FromAffineUncompressed(bytes []byte) (Point, error) + CurveName() string + SumOfProducts(points []Point, scalars []Scalar) Point +} + +type PairingPoint interface { + Point + OtherGroup() PairingPoint + Pairing(rhs PairingPoint) Scalar + MultiPairing(...PairingPoint) Scalar +} + +func pointMarshalBinary(point Point) ([]byte, error) { + // Always stores points in compressed form + // The first bytes are the curve name + // separated by a colon followed by the compressed point + // bytes + t := point.ToAffineCompressed() + name := []byte(point.CurveName()) + output := make([]byte, len(name)+1+len(t)) + copy(output[:len(name)], name) + output[len(name)] = byte(':') + copy(output[len(output)-len(t):], t) + return output, nil +} + +func pointUnmarshalBinary(input []byte) (Point, error) { + if len(input) < scalarBytes+1+len(P256Name) { + return nil, fmt.Errorf("invalid byte sequence") + } + sep := byte(':') + i := 0 + for ; i < len(input); i++ { + if input[i] == sep { + break + } + } + name := string(input[:i]) + curve := GetCurveByName(name) + if curve == nil { + return nil, fmt.Errorf("unrecognized curve") + } + return curve.Point.FromAffineCompressed(input[i+1:]) +} + +func pointMarshalText(point Point) ([]byte, error) { + // Always stores points in compressed form + // The first bytes are the curve name + // separated by a colon followed by the compressed point + // bytes + t := point.ToAffineCompressed() + name := []byte(point.CurveName()) + output := make([]byte, len(name)+1+len(t)*2) + copy(output[:len(name)], name) + output[len(name)] = byte(':') + hex.Encode(output[len(output)-len(t)*2:], t) + return output, nil +} + +func pointUnmarshalText(input []byte) (Point, error) { + if len(input) < scalarBytes*2+1+len(P256Name) { + return nil, fmt.Errorf("invalid byte sequence") + } + sep := byte(':') + i := 0 + for ; i < len(input); i++ { + if input[i] == sep { + break + } + } + name := string(input[:i]) + curve := GetCurveByName(name) + if curve == nil { + return nil, fmt.Errorf("unrecognized curve") + } + buffer := make([]byte, (len(input)-i)/2) + _, err := hex.Decode(buffer, input[i+1:]) + if err != nil { + return nil, err + } + return curve.Point.FromAffineCompressed(buffer) +} + +func pointMarshalJson(point Point) ([]byte, error) { + m := make(map[string]string, 2) + m["type"] = point.CurveName() + m["value"] = hex.EncodeToString(point.ToAffineCompressed()) + return json.Marshal(m) +} + +func pointUnmarshalJson(input []byte) (Point, error) { + var m map[string]string + + err := json.Unmarshal(input, &m) + if err != nil { + return nil, err + } + curve := GetCurveByName(m["type"]) + if curve == nil { + return nil, fmt.Errorf("invalid type") + } + p, err := hex.DecodeString(m["value"]) + if err != nil { + return nil, err + } + P, err := curve.Point.FromAffineCompressed(p) + if err != nil { + return nil, err + } + return P, nil +} + +// Curve represents a named elliptic curve with a scalar field and point group +type Curve struct { + Scalar Scalar + Point Point + Name string +} + +func (c Curve) ScalarBaseMult(sc Scalar) Point { + return c.Point.Generator().Mul(sc) +} + +func (c Curve) NewGeneratorPoint() Point { + return c.Point.Generator() +} + +func (c Curve) NewIdentityPoint() Point { + return c.Point.Identity() +} + +func (c Curve) NewScalar() Scalar { + return c.Scalar.Zero() +} + +// ToEllipticCurve returns the equivalent of this curve as the go interface `elliptic.Curve` +func (c Curve) ToEllipticCurve() (elliptic.Curve, error) { + err := fmt.Errorf("can't convert %s", c.Name) + switch c.Name { + case K256Name: + return K256Curve(), nil + case BLS12381G1Name: + return nil, err + case BLS12381G2Name: + return nil, err + case BLS12831Name: + return nil, err + case P256Name: + return NistP256Curve(), nil + case ED25519Name: + return nil, err + case PallasName: + return nil, err + case BLS12377G1Name: + return nil, err + case BLS12377G2Name: + return nil, err + case BLS12377Name: + return nil, err + default: + return nil, err + } +} + +// PairingCurve represents a named elliptic curve +// that supports pairings +type PairingCurve struct { + Scalar PairingScalar + PointG1 PairingPoint + PointG2 PairingPoint + GT Scalar + Name string +} + +func (c PairingCurve) ScalarG1BaseMult(sc Scalar) PairingPoint { + return c.PointG1.Generator().Mul(sc).(PairingPoint) +} + +func (c PairingCurve) ScalarG2BaseMult(sc Scalar) PairingPoint { + return c.PointG2.Generator().Mul(sc).(PairingPoint) +} + +func (c PairingCurve) NewG1GeneratorPoint() PairingPoint { + return c.PointG1.Generator().(PairingPoint) +} + +func (c PairingCurve) NewG2GeneratorPoint() PairingPoint { + return c.PointG2.Generator().(PairingPoint) +} + +func (c PairingCurve) NewG1IdentityPoint() PairingPoint { + return c.PointG1.Identity().(PairingPoint) +} + +func (c PairingCurve) NewG2IdentityPoint() PairingPoint { + return c.PointG2.Identity().(PairingPoint) +} + +func (c PairingCurve) NewScalar() PairingScalar { + return c.Scalar.Zero().(PairingScalar) +} + +// GetCurveByName returns the correct `Curve` given the name +func GetCurveByName(name string) *Curve { + switch name { + case K256Name: + return K256() + case BLS12381G1Name: + return BLS12381G1() + case BLS12381G2Name: + return BLS12381G2() + case BLS12831Name: + return BLS12381G1() + case P256Name: + return P256() + case ED25519Name: + return ED25519() + case PallasName: + return PALLAS() + case BLS12377G1Name: + return BLS12377G1() + case BLS12377G2Name: + return BLS12377G2() + case BLS12377Name: + return BLS12377G1() + default: + return nil + } +} + +func GetPairingCurveByName(name string) *PairingCurve { + switch name { + case BLS12381G1Name: + return BLS12381(BLS12381G1().NewIdentityPoint()) + case BLS12381G2Name: + return BLS12381(BLS12381G2().NewIdentityPoint()) + case BLS12831Name: + return BLS12381(BLS12381G1().NewIdentityPoint()) + default: + return nil + } +} + +// BLS12381G1 returns the BLS12-381 curve with points in G1 +func BLS12381G1() *Curve { + bls12381g1Initonce.Do(bls12381g1Init) + return &bls12381g1 +} + +func bls12381g1Init() { + bls12381g1 = Curve{ + Scalar: &ScalarBls12381{ + Value: bls12381.Bls12381FqNew(), + point: new(PointBls12381G1), + }, + Point: new(PointBls12381G1).Identity(), + Name: BLS12381G1Name, + } +} + +// BLS12381G2 returns the BLS12-381 curve with points in G2 +func BLS12381G2() *Curve { + bls12381g2Initonce.Do(bls12381g2Init) + return &bls12381g2 +} + +func bls12381g2Init() { + bls12381g2 = Curve{ + Scalar: &ScalarBls12381{ + Value: bls12381.Bls12381FqNew(), + point: new(PointBls12381G2), + }, + Point: new(PointBls12381G2).Identity(), + Name: BLS12381G2Name, + } +} + +func BLS12381(preferredPoint Point) *PairingCurve { + return &PairingCurve{ + Scalar: &ScalarBls12381{ + Value: bls12381.Bls12381FqNew(), + point: preferredPoint, + }, + PointG1: &PointBls12381G1{ + Value: new(bls12381.G1).Identity(), + }, + PointG2: &PointBls12381G2{ + Value: new(bls12381.G2).Identity(), + }, + GT: &ScalarBls12381Gt{ + Value: new(bls12381.Gt).SetOne(), + }, + Name: BLS12831Name, + } +} + +// BLS12377G1 returns the BLS12-377 curve with points in G1 +func BLS12377G1() *Curve { + bls12377g1Initonce.Do(bls12377g1Init) + return &bls12377g1 +} + +func bls12377g1Init() { + bls12377g1 = Curve{ + Scalar: &ScalarBls12377{ + value: new(big.Int), + point: new(PointBls12377G1), + }, + Point: new(PointBls12377G1).Identity(), + Name: BLS12377G1Name, + } +} + +// BLS12377G2 returns the BLS12-377 curve with points in G2 +func BLS12377G2() *Curve { + bls12377g2Initonce.Do(bls12377g2Init) + return &bls12377g2 +} + +func bls12377g2Init() { + bls12377g2 = Curve{ + Scalar: &ScalarBls12377{ + value: new(big.Int), + point: new(PointBls12377G2), + }, + Point: new(PointBls12377G2).Identity(), + Name: BLS12377G2Name, + } +} + +// K256 returns the secp256k1 curve +func K256() *Curve { + k256Initonce.Do(k256Init) + return &k256 +} + +func k256Init() { + k256 = Curve{ + Scalar: new(ScalarK256).Zero(), + Point: new(PointK256).Identity(), + Name: K256Name, + } +} + +func P256() *Curve { + p256Initonce.Do(p256Init) + return &p256 +} + +func p256Init() { + p256 = Curve{ + Scalar: new(ScalarP256).Zero(), + Point: new(PointP256).Identity(), + Name: P256Name, + } +} + +func ED25519() *Curve { + ed25519Initonce.Do(ed25519Init) + return &ed25519 +} + +func ed25519Init() { + ed25519 = Curve{ + Scalar: new(ScalarEd25519).Zero(), + Point: new(PointEd25519).Identity(), + Name: ED25519Name, + } +} + +func PALLAS() *Curve { + pallasInitonce.Do(pallasInit) + return &pallas +} + +func pallasInit() { + pallas = Curve{ + Scalar: new(ScalarPallas).Zero(), + Point: new(PointPallas).Identity(), + Name: PallasName, + } +} + +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.2.1 +func osswu3mod4(u *big.Int, p *sswuParams) (x, y *big.Int) { + params := p.Params + field := NewField(p.Params.P) + + tv1 := field.NewElement(u) + tv1 = tv1.Mul(tv1) // tv1 = u^2 + tv3 := field.NewElement(p.Z).Mul(tv1) // tv3 = Z * tv1 + tv2 := tv3.Mul(tv3) // tv2 = tv3^2 + xd := tv2.Add(tv3) // xd = tv2 + tv3 + x1n := xd.Add(field.One()) // x1n = (xd + 1) + x1n = x1n.Mul(field.NewElement(p.B)) // x1n * B + aNeg := field.NewElement(p.A).Neg() + xd = xd.Mul(aNeg) // xd = -A * xd + + if xd.Value.Cmp(big.NewInt(0)) == 0 { + xd = field.NewElement(p.Z).Mul(field.NewElement(p.A)) // xd = Z * A + } + + tv2 = xd.Mul(xd) // tv2 = xd^2 + gxd := tv2.Mul(xd) // gxd = tv2 * xd + tv2 = tv2.Mul(field.NewElement(p.A)) // tv2 = A * tv2 + + gx1 := x1n.Mul(x1n) // gx1 = x1n^2 + gx1 = gx1.Add(tv2) // gx1 = gx1 + tv2 + gx1 = gx1.Mul(x1n) // gx1 = gx1 * x1n + tv2 = gxd.Mul(field.NewElement(p.B)) // tv2 = B * gxd + gx1 = gx1.Add(tv2) // gx1 = gx1 + tv2 + + tv4 := gxd.Mul(gxd) // tv4 = gxd^2 + tv2 = gx1.Mul(gxd) // tv2 = gx1 * gxd + tv4 = tv4.Mul(tv2) //tv4 = tv4 * tv2 + + y1 := tv4.Pow(field.NewElement(p.C1)) + y1 = y1.Mul(tv2) //y1 = y1 * tv2 + x2n := tv3.Mul(x1n) // x2n = tv3 * x1n + + y2 := y1.Mul(field.NewElement(p.C2)) // y2 = y1 * c2 + y2 = y2.Mul(tv1) // y2 = y2 * tv1 + y2 = y2.Mul(field.NewElement(u)) // y2 = y2 * u + + tv2 = y1.Mul(y1) // tv2 = y1^2 + + tv2 = tv2.Mul(gxd) // tv2 = tv2 * gxd + + e2 := tv2.Value.Cmp(gx1.Value) == 0 + + // If e2, x = x1, else x = x2 + if e2 { + x = x1n.Value + } else { + x = x2n.Value + } + // xn / xd + x.Mul(x, new(big.Int).ModInverse(xd.Value, params.P)) + x.Mod(x, params.P) + + // If e2, y = y1, else y = y2 + if e2 { + y = y1.Value + } else { + y = y2.Value + } + + uBytes := u.Bytes() + yBytes := y.Bytes() + + usign := uBytes[len(uBytes)-1] & 1 + ysign := yBytes[len(yBytes)-1] & 1 + + // Fix sign of y + if usign != ysign { + y.Neg(y) + y.Mod(y, params.P) + } + + return +} + +func expandMsgXmd(h hash.Hash, msg, domain []byte, outLen int) ([]byte, error) { + domainLen := uint8(len(domain)) + if domainLen > 255 { + return nil, fmt.Errorf("invalid domain length") + } + // DST_prime = DST || I2OSP(len(DST), 1) + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + _, _ = h.Write(make([]byte, h.BlockSize())) + _, _ = h.Write(msg) + _, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)}) + _, _ = h.Write([]byte{0}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b0 := h.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.Reset() + _, _ = h.Write(b0) + _, _ = h.Write([]byte{1}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b1 := h.Sum(nil) + + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + ell := (outLen + h.Size() - 1) / h.Size() + bi := b1 + out := make([]byte, outLen) + for i := 1; i < ell; i++ { + h.Reset() + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + tmp := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + tmp[j] = b0[j] ^ bi[j] + } + _, _ = h.Write(tmp) + _, _ = h.Write([]byte{1 + uint8(i)}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + + // b_1 || ... || b_(ell - 1) + copy(out[(i-1)*h.Size():i*h.Size()], bi[:]) + bi = h.Sum(nil) + } + // b_ell + copy(out[(ell-1)*h.Size():], bi[:]) + return out[:outLen], nil +} + +func bhex(s string) *big.Int { + r, _ := new(big.Int).SetString(s, 16) + return r +} + +type sswuParams struct { + Params *elliptic.CurveParams + C1, C2, A, B, Z *big.Int +} + +// sumOfProductsPippenger implements a version of Pippenger's algorithm. +// +// The algorithm works as follows: +// +// Let `n` be a number of point-scalar pairs. +// Let `w` be a window of bits (6..8, chosen based on `n`, see cost factor). +// +// 1. Prepare `2^(w-1) - 1` buckets with indices `[1..2^(w-1))` initialized with identity points. +// Bucket 0 is not needed as it would contain points multiplied by 0. +// 2. Convert scalars to a radix-`2^w` representation with signed digits in `[-2^w/2, 2^w/2]`. +// Note: only the last digit may equal `2^w/2`. +// 3. Starting with the last window, for each point `i=[0..n)` add it to a a bucket indexed by +// the point's scalar's value in the window. +// 4. Once all points in a window are sorted into buckets, add buckets by multiplying each +// by their index. Efficient way of doing it is to start with the last bucket and compute two sums: +// intermediate sum from the last to the first, and the full sum made of all intermediate sums. +// 5. Shift the resulting sum of buckets by `w` bits by using `w` doublings. +// 6. Add to the return value. +// 7. Repeat the loop. +// +// Approximate cost w/o wNAF optimizations (A = addition, D = doubling): +// +// ```ascii +// cost = (n*A + 2*(2^w/2)*A + w*D + A)*256/w +// | | | | | +// | | | | looping over 256/w windows +// | | | adding to the result +// sorting points | shifting the sum by w bits (to the next window, starting from last window) +// one by one | +// into buckets adding/subtracting all buckets +// multiplied by their indexes +// using a sum of intermediate sums +// ``` +// +// For large `n`, dominant factor is (n*256/w) additions. +// However, if `w` is too big and `n` is not too big, then `(2^w/2)*A` could dominate. +// Therefore, the optimal choice of `w` grows slowly as `n` grows. +// +// For constant time we use a fixed window of 6 +// +// This algorithm is adapted from section 4 of . +// and https://cacr.uwaterloo.ca/techreports/2010/cacr2010-26.pdf +func sumOfProductsPippenger(points []Point, scalars []*big.Int) Point { + if len(points) != len(scalars) { + return nil + } + + const w = 6 + + bucketSize := (1 << w) - 1 + windows := make([]Point, 255/w+1) + for i := range windows { + windows[i] = points[0].Identity() + } + bucket := make([]Point, bucketSize) + + for j := 0; j < len(windows); j++ { + for i := 0; i < bucketSize; i++ { + bucket[i] = points[0].Identity() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(w*j)).Int64()) + if index != 0 { + bucket[index-1] = bucket[index-1].Add(points[i]) + } + } + + acc, sum := windows[j].Identity(), windows[j].Identity() + + for i := bucketSize - 1; i >= 0; i-- { + sum = sum.Add(bucket[i]) + acc = acc.Add(sum) + } + windows[j] = acc + } + + acc := windows[0].Identity() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < w; j++ { + acc = acc.Double() + } + acc = acc.Add(windows[i]) + } + return acc +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_point.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_point.go new file mode 100644 index 0000000000..3541375f4d --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_point.go @@ -0,0 +1,256 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + "encoding/json" + "fmt" + "math/big" + + "github.com/btcsuite/btcd/btcec" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core" +) + +var curveNameToId = map[string]byte{ + "secp256k1": 0, + "P-224": 1, + "P-256": 2, + "P-384": 3, + "P-521": 4, +} + +var curveIdToName = map[byte]func() elliptic.Curve{ + 0: func() elliptic.Curve { return btcec.S256() }, + 1: elliptic.P224, + 2: elliptic.P256, + 3: elliptic.P384, + 4: elliptic.P521, +} + +var curveMapper = map[string]func() elliptic.Curve{ + "secp256k1": func() elliptic.Curve { return btcec.S256() }, + "P-224": elliptic.P224, + "P-256": elliptic.P256, + "P-384": elliptic.P384, + "P-521": elliptic.P521, +} + +// EcPoint represents an elliptic curve Point +type EcPoint struct { + Curve elliptic.Curve + X, Y *big.Int +} + +// EcPointJson encapsulates the data that is serialized to JSON +// used internally and not for external use. Public so other pieces +// can use for serialization +type EcPointJson struct { + CurveName string + X, Y *big.Int +} + +// MarshalJSON serializes +func (a EcPoint) MarshalJSON() ([]byte, error) { + return json.Marshal(EcPointJson{ + CurveName: a.Curve.Params().Name, + X: a.X, + Y: a.Y, + }) +} + +func (a *EcPoint) UnmarshalJSON(bytes []byte) error { + data := new(EcPointJson) + err := json.Unmarshal(bytes, data) + if err != nil { + return err + } + if mapper, ok := curveMapper[data.CurveName]; ok { + a.Curve = mapper() + a.X = data.X + a.Y = data.Y + return nil + } + return fmt.Errorf("unknown curve deserialized") +} + +func (a *EcPoint) MarshalBinary() ([]byte, error) { + result := [65]byte{} + if code, ok := curveNameToId[a.Curve.Params().Name]; ok { + result[0] = code + a.X.FillBytes(result[1:33]) + a.Y.FillBytes(result[33:65]) + return result[:], nil + } + return nil, fmt.Errorf("unknown curve serialized") +} + +func (a *EcPoint) UnmarshalBinary(data []byte) error { + if mapper, ok := curveIdToName[data[0]]; ok { + a.Curve = mapper() + a.X = new(big.Int).SetBytes(data[1:33]) + a.Y = new(big.Int).SetBytes(data[33:65]) + return nil + } + return fmt.Errorf("unknown curve deserialized") +} + +func (a EcPoint) IsValid() bool { + return a.IsOnCurve() || a.IsIdentity() +} + +func (a EcPoint) IsOnCurve() bool { + return a.Curve.IsOnCurve(a.X, a.Y) +} + +// IsIdentity returns true if this Point is the Point at infinity +func (a EcPoint) IsIdentity() bool { + x := core.ConstantTimeEqByte(a.X, core.Zero) + y := core.ConstantTimeEqByte(a.Y, core.Zero) + return (x & y) == 1 +} + +// Equals return true if a + b have the same x,y coordinates +func (a EcPoint) Equals(b *EcPoint) bool { + if !sameCurve(&a, b) { + return false + } + // Next, compare coords to determine equality + x := core.ConstantTimeEqByte(a.X, b.X) + y := core.ConstantTimeEqByte(a.Y, b.Y) + return (x & y) == 1 +} + +// IsBasePoint returns true if this Point is curve's base Point +func (a EcPoint) IsBasePoint() bool { + p := a.Curve.Params() + x := core.ConstantTimeEqByte(a.X, p.Gx) + y := core.ConstantTimeEqByte(a.Y, p.Gy) + return (x & y) == 1 +} + +// Normalizes the Scalar to a positive element smaller than the base Point order. +func reduceModN(curve elliptic.Curve, k *big.Int) *big.Int { + return new(big.Int).Mod(k, curve.Params().N) +} + +// Add performs elliptic curve addition on two points +func (a *EcPoint) Add(b *EcPoint) (*EcPoint, error) { + // Validate parameters + if a == nil || b == nil { + return nil, internal.ErrNilArguments + } + // Only add points from the same curve + if !sameCurve(a, b) { + return nil, internal.ErrPointsDistinctCurves + } + p := &EcPoint{Curve: a.Curve} + p.X, p.Y = a.Curve.Add(a.X, a.Y, b.X, b.Y) + if !p.IsValid() { + return nil, internal.ErrNotOnCurve + } + return p, nil +} + +// Neg returns the negation of a Weierstrass Point. +func (a *EcPoint) Neg() (*EcPoint, error) { + // Validate parameters + if a == nil { + return nil, internal.ErrNilArguments + } + // Only add points from the same curve + p := &EcPoint{Curve: a.Curve, X: a.X, Y: new(big.Int).Sub(a.Curve.Params().P, a.Y)} + if !p.IsValid() { + return nil, internal.ErrNotOnCurve + } + return p, nil +} + +// ScalarMult multiplies this Point by a Scalar +func (a *EcPoint) ScalarMult(k *big.Int) (*EcPoint, error) { + if a == nil || k == nil { + return nil, fmt.Errorf("cannot multiply nil Point or element") + } + n := reduceModN(a.Curve, k) + p := new(EcPoint) + p.Curve = a.Curve + p.X, p.Y = a.Curve.ScalarMult(a.X, a.Y, n.Bytes()) + if !p.IsValid() { + return nil, fmt.Errorf("result not on the curve") + } + return p, nil +} + +// NewScalarBaseMult creates a Point from the base Point multiplied by a field element +func NewScalarBaseMult(curve elliptic.Curve, k *big.Int) (*EcPoint, error) { + if curve == nil || k == nil { + return nil, fmt.Errorf("nil parameters are not supported") + } + n := reduceModN(curve, k) + p := new(EcPoint) + p.Curve = curve + p.X, p.Y = curve.ScalarBaseMult(n.Bytes()) + if !p.IsValid() { + return nil, fmt.Errorf("result not on the curve") + } + return p, nil +} + +// Bytes returns the bytes represented by this Point with x || y +func (a EcPoint) Bytes() []byte { + fieldSize := internal.CalcFieldSize(a.Curve) + out := make([]byte, fieldSize*2) + + a.X.FillBytes(out[0:fieldSize]) + a.Y.FillBytes(out[fieldSize : fieldSize*2]) + return out +} + +// PointFromBytesUncompressed outputs uncompressed X || Y similar to +// https://www.secg.org/sec1-v1.99.dif.pdf section 2.2 and 2.3 +func PointFromBytesUncompressed(curve elliptic.Curve, b []byte) (*EcPoint, error) { + fieldSize := internal.CalcFieldSize(curve) + if len(b) != fieldSize*2 { + return nil, fmt.Errorf("invalid number of bytes") + } + p := &EcPoint{ + Curve: curve, + X: new(big.Int).SetBytes(b[:fieldSize]), + Y: new(big.Int).SetBytes(b[fieldSize:]), + } + if !p.IsValid() { + return nil, fmt.Errorf("invalid Point") + } + return p, nil +} + +// sameCurve determines if points a,b appear to be from the same curve +func sameCurve(a, b *EcPoint) bool { + // Handle identical pointers and double-nil + if a == b { + return true + } + + // Handle one nil pointer + if a == nil || b == nil { + return false + } + + aParams := a.Curve.Params() + bParams := b.Curve.Params() + + // Use curve order and name + return aParams.P == bParams.P && + aParams.N == bParams.N && + aParams.B == bParams.B && + aParams.BitSize == bParams.BitSize && + aParams.Gx == bParams.Gx && + aParams.Gy == bParams.Gy && + aParams.Name == bParams.Name +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_scalar.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_scalar.go new file mode 100644 index 0000000000..6138878886 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ec_scalar.go @@ -0,0 +1,351 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + crand "crypto/rand" + "crypto/sha512" + "fmt" + "io" + "math/big" + + "filippo.io/edwards25519" + "github.com/btcsuite/btcd/btcec" + "github.com/bwesterb/go-ristretto" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core" + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" +) + +type EcScalar interface { + Add(x, y *big.Int) *big.Int + Sub(x, y *big.Int) *big.Int + Neg(x *big.Int) *big.Int + Mul(x, y *big.Int) *big.Int + Hash(input []byte) *big.Int + Div(x, y *big.Int) *big.Int + Random() (*big.Int, error) + IsValid(x *big.Int) bool + Bytes(x *big.Int) []byte // fixed-length byte array +} + +type K256Scalar struct{} + +// Static interface assertion +var _ EcScalar = (*K256Scalar)(nil) + +// warning: the Euclidean alg which Mod uses is not constant-time. + +func NewK256Scalar() *K256Scalar { + return &K256Scalar{} +} + +func (k K256Scalar) Add(x, y *big.Int) *big.Int { + v := new(big.Int).Add(x, y) + v.Mod(v, btcec.S256().N) + return v +} + +func (k K256Scalar) Sub(x, y *big.Int) *big.Int { + v := new(big.Int).Sub(x, y) + v.Mod(v, btcec.S256().N) + return v +} + +func (k K256Scalar) Neg(x *big.Int) *big.Int { + v := new(big.Int).Sub(btcec.S256().N, x) + v.Mod(v, btcec.S256().N) + return v +} + +func (k K256Scalar) Mul(x, y *big.Int) *big.Int { + v := new(big.Int).Mul(x, y) + v.Mod(v, btcec.S256().N) + return v +} + +func (k K256Scalar) Div(x, y *big.Int) *big.Int { + t := new(big.Int).ModInverse(y, btcec.S256().N) + return k.Mul(x, t) +} + +func (k K256Scalar) Hash(input []byte) *big.Int { + return new(ScalarK256).Hash(input).BigInt() +} + +func (k K256Scalar) Random() (*big.Int, error) { + b := make([]byte, 48) + n, err := crand.Read(b) + if err != nil { + return nil, err + } + if n != 48 { + return nil, fmt.Errorf("insufficient bytes read") + } + v := new(big.Int).SetBytes(b) + v.Mod(v, btcec.S256().N) + return v, nil +} + +func (k K256Scalar) IsValid(x *big.Int) bool { + return core.In(x, btcec.S256().N) == nil +} + +func (k K256Scalar) Bytes(x *big.Int) []byte { + bytes := make([]byte, 32) + x.FillBytes(bytes) // big-endian; will left-pad. + return bytes +} + +type P256Scalar struct{} + +// Static interface assertion +var _ EcScalar = (*P256Scalar)(nil) + +func NewP256Scalar() *P256Scalar { + return &P256Scalar{} +} + +func (k P256Scalar) Add(x, y *big.Int) *big.Int { + v := new(big.Int).Add(x, y) + v.Mod(v, elliptic.P256().Params().N) + return v +} + +func (k P256Scalar) Sub(x, y *big.Int) *big.Int { + v := new(big.Int).Sub(x, y) + v.Mod(v, elliptic.P256().Params().N) + return v +} + +func (k P256Scalar) Neg(x *big.Int) *big.Int { + v := new(big.Int).Sub(elliptic.P256().Params().N, x) + v.Mod(v, elliptic.P256().Params().N) + return v +} + +func (k P256Scalar) Mul(x, y *big.Int) *big.Int { + v := new(big.Int).Mul(x, y) + v.Mod(v, elliptic.P256().Params().N) + return v +} + +func (k P256Scalar) Div(x, y *big.Int) *big.Int { + t := new(big.Int).ModInverse(y, elliptic.P256().Params().N) + return k.Mul(x, t) +} + +func (k P256Scalar) Hash(input []byte) *big.Int { + return new(ScalarP256).Hash(input).BigInt() +} + +func (k P256Scalar) Random() (*big.Int, error) { + b := make([]byte, 48) + n, err := crand.Read(b) + if err != nil { + return nil, err + } + if n != 48 { + return nil, fmt.Errorf("insufficient bytes read") + } + v := new(big.Int).SetBytes(b) + v.Mod(v, elliptic.P256().Params().N) + return v, nil +} + +func (k P256Scalar) IsValid(x *big.Int) bool { + return core.In(x, elliptic.P256().Params().N) == nil +} + +func (k P256Scalar) Bytes(x *big.Int) []byte { + bytes := make([]byte, 32) + x.FillBytes(bytes) // big-endian; will left-pad. + return bytes +} + +type Bls12381Scalar struct{} + +// Static interface assertion +var _ EcScalar = (*Bls12381Scalar)(nil) + +func NewBls12381Scalar() *Bls12381Scalar { + return &Bls12381Scalar{} +} + +func (k Bls12381Scalar) Add(x, y *big.Int) *big.Int { + a := bls12381.Bls12381FqNew().SetBigInt(x) + b := bls12381.Bls12381FqNew().SetBigInt(y) + return a.Add(a, b).BigInt() +} + +func (k Bls12381Scalar) Sub(x, y *big.Int) *big.Int { + a := bls12381.Bls12381FqNew().SetBigInt(x) + b := bls12381.Bls12381FqNew().SetBigInt(y) + return a.Sub(a, b).BigInt() +} + +func (k Bls12381Scalar) Neg(x *big.Int) *big.Int { + a := bls12381.Bls12381FqNew().SetBigInt(x) + return a.Neg(a).BigInt() +} + +func (k Bls12381Scalar) Mul(x, y *big.Int) *big.Int { + a := bls12381.Bls12381FqNew().SetBigInt(x) + b := bls12381.Bls12381FqNew().SetBigInt(y) + return a.Mul(a, b).BigInt() +} + +func (k Bls12381Scalar) Div(x, y *big.Int) *big.Int { + c := bls12381.Bls12381FqNew() + a := bls12381.Bls12381FqNew().SetBigInt(x) + b := bls12381.Bls12381FqNew().SetBigInt(y) + _, wasInverted := c.Invert(b) + c.Mul(a, c) + tt := map[bool]int{false: 0, true: 1} + return a.CMove(a, c, tt[wasInverted]).BigInt() +} + +func (k Bls12381Scalar) Hash(input []byte) *big.Int { + return new(ScalarBls12381).Hash(input).BigInt() +} + +func (k Bls12381Scalar) Random() (*big.Int, error) { + a := BLS12381G1().NewScalar().Random(crand.Reader) + if a == nil { + return nil, fmt.Errorf("invalid random value") + } + return a.BigInt(), nil +} + +func (k Bls12381Scalar) Bytes(x *big.Int) []byte { + bytes := make([]byte, 32) + x.FillBytes(bytes) // big-endian; will left-pad. + return bytes +} + +func (k Bls12381Scalar) IsValid(x *big.Int) bool { + a := bls12381.Bls12381FqNew().SetBigInt(x) + return a.BigInt().Cmp(x) == 0 +} + +// taken from https://datatracker.ietf.org/doc/html/rfc8032 +var ed25519N, _ = new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16) + +type Ed25519Scalar struct{} + +// Static interface assertion +var _ EcScalar = (*Ed25519Scalar)(nil) + +func NewEd25519Scalar() *Ed25519Scalar { + return &Ed25519Scalar{} +} + +func (k Ed25519Scalar) Add(x, y *big.Int) *big.Int { + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + b, err := internal.BigInt2Ed25519Scalar(y) + if err != nil { + panic(err) + } + a.Add(a, b) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes())) +} + +func (k Ed25519Scalar) Sub(x, y *big.Int) *big.Int { + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + b, err := internal.BigInt2Ed25519Scalar(y) + if err != nil { + panic(err) + } + a.Subtract(a, b) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes())) +} + +func (k Ed25519Scalar) Neg(x *big.Int) *big.Int { + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + a.Negate(a) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes())) +} + +func (k Ed25519Scalar) Mul(x, y *big.Int) *big.Int { + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + b, err := internal.BigInt2Ed25519Scalar(y) + if err != nil { + panic(err) + } + a.Multiply(a, b) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes())) +} + +func (k Ed25519Scalar) Div(x, y *big.Int) *big.Int { + b, err := internal.BigInt2Ed25519Scalar(y) + if err != nil { + panic(err) + } + b.Invert(b) + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + a.Multiply(a, b) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(a.Bytes())) +} + +func (k Ed25519Scalar) Hash(input []byte) *big.Int { + v := new(ristretto.Scalar).Derive(input) + var data [32]byte + v.BytesInto(&data) + return new(big.Int).SetBytes(internal.ReverseScalarBytes(data[:])) +} + +func (k Ed25519Scalar) Bytes(x *big.Int) []byte { + a, err := internal.BigInt2Ed25519Scalar(x) + if err != nil { + panic(err) + } + return internal.ReverseScalarBytes(a.Bytes()) +} + +func (k Ed25519Scalar) Random() (*big.Int, error) { + return k.RandomWithReader(crand.Reader) +} + +func (k Ed25519Scalar) RandomWithReader(r io.Reader) (*big.Int, error) { + b := make([]byte, 64) + n, err := r.Read(b) + if err != nil { + return nil, err + } + if n != 64 { + return nil, fmt.Errorf("insufficient bytes read") + } + digest := sha512.Sum512(b) + var hBytes [32]byte + copy(hBytes[:], digest[:]) + s, err := edwards25519.NewScalar().SetBytesWithClamping(hBytes[:]) + if err != nil { + return nil, err + } + return new(big.Int).SetBytes(internal.ReverseScalarBytes(s.Bytes())), nil +} + +func (k Ed25519Scalar) IsValid(x *big.Int) bool { + return x.Cmp(ed25519N) == -1 +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/ecdsa.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ecdsa.go new file mode 100644 index 0000000000..2b2e9b4da9 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ecdsa.go @@ -0,0 +1,38 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/ecdsa" + "math/big" +) + +// EcdsaVerify runs a curve- or algorithm-specific ECDSA verification function on input +// an ECDSA public (verification) key, a message digest, and an ECDSA signature. +// It must return true if all the parameters are sane and the ECDSA signature is valid, +// and false otherwise +type EcdsaVerify func(pubKey *EcPoint, hash []byte, signature *EcdsaSignature) bool + +// EcdsaSignature represents a (composite) digital signature +type EcdsaSignature struct { + V int + R, S *big.Int +} + +// Static type assertion +var _ EcdsaVerify = VerifyEcdsa + +// Verifies ECDSA signature using core types. +func VerifyEcdsa(pk *EcPoint, hash []byte, sig *EcdsaSignature) bool { + return ecdsa.Verify( + &ecdsa.PublicKey{ + Curve: pk.Curve, + X: pk.X, + Y: pk.Y, + }, + hash, sig.R, sig.S) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/ed25519_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ed25519_curve.go new file mode 100644 index 0000000000..c52167bc8c --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/ed25519_curve.go @@ -0,0 +1,786 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "bytes" + "crypto/sha512" + "crypto/subtle" + "fmt" + "io" + "math/big" + + "filippo.io/edwards25519" + "filippo.io/edwards25519/field" + "github.com/bwesterb/go-ristretto" + ed "github.com/bwesterb/go-ristretto/edwards25519" + + "github.com/coinbase/kryptology/internal" +) + +type ScalarEd25519 struct { + value *edwards25519.Scalar +} + +type PointEd25519 struct { + value *edwards25519.Point +} + +var scOne, _ = edwards25519.NewScalar().SetCanonicalBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + +func (s *ScalarEd25519) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarEd25519) Hash(bytes []byte) Scalar { + v := new(ristretto.Scalar).Derive(bytes) + var data [32]byte + v.BytesInto(&data) + value, err := edwards25519.NewScalar().SetCanonicalBytes(data[:]) + if err != nil { + return nil + } + return &ScalarEd25519{value} +} + +func (s *ScalarEd25519) Zero() Scalar { + return &ScalarEd25519{ + value: edwards25519.NewScalar(), + } +} + +func (s *ScalarEd25519) One() Scalar { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Set(scOne), + } +} + +func (s *ScalarEd25519) IsZero() bool { + i := byte(0) + for _, b := range s.value.Bytes() { + i |= b + } + return i == 0 +} + +func (s *ScalarEd25519) IsOne() bool { + data := s.value.Bytes() + i := byte(0) + for j := 1; j < len(data); j++ { + i |= data[j] + } + return i == 0 && data[0] == 1 +} + +func (s *ScalarEd25519) IsOdd() bool { + return s.value.Bytes()[0]&1 == 1 +} + +func (s *ScalarEd25519) IsEven() bool { + return s.value.Bytes()[0]&1 == 0 +} + +func (s *ScalarEd25519) New(input int) Scalar { + var data [64]byte + i := input + if input < 0 { + i = -input + } + data[0] = byte(i) + data[1] = byte(i >> 8) + data[2] = byte(i >> 16) + data[3] = byte(i >> 24) + value, err := edwards25519.NewScalar().SetUniformBytes(data[:]) + if err != nil { + return nil + } + if input < 0 { + value.Negate(value) + } + + return &ScalarEd25519{ + value, + } +} + +func (s *ScalarEd25519) Cmp(rhs Scalar) int { + r := s.Sub(rhs) + if r != nil && r.IsZero() { + return 0 + } else { + return -2 + } +} + +func (s *ScalarEd25519) Square() Scalar { + value := edwards25519.NewScalar().Multiply(s.value, s.value) + return &ScalarEd25519{value} +} + +func (s *ScalarEd25519) Double() Scalar { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Add(s.value, s.value), + } +} + +func (s *ScalarEd25519) Invert() (Scalar, error) { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Invert(s.value), + }, nil +} + +func (s *ScalarEd25519) Sqrt() (Scalar, error) { + bi25519, _ := new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16) + x := s.BigInt() + x.ModSqrt(x, bi25519) + return s.SetBigInt(x) +} + +func (s *ScalarEd25519) Cube() Scalar { + value := edwards25519.NewScalar().Multiply(s.value, s.value) + value.Multiply(value, s.value) + return &ScalarEd25519{value} +} + +func (s *ScalarEd25519) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarEd25519) + if ok { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Add(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarEd25519) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarEd25519) + if ok { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Subtract(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarEd25519) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarEd25519) + if ok { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Multiply(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarEd25519) MulAdd(y, z Scalar) Scalar { + yy, ok := y.(*ScalarEd25519) + if !ok { + return nil + } + zz, ok := z.(*ScalarEd25519) + if !ok { + return nil + } + return &ScalarEd25519{value: edwards25519.NewScalar().MultiplyAdd(s.value, yy.value, zz.value)} +} + +func (s *ScalarEd25519) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarEd25519) + if ok { + value := edwards25519.NewScalar().Invert(r.value) + value.Multiply(value, s.value) + return &ScalarEd25519{value} + } else { + return nil + } +} + +func (s *ScalarEd25519) Neg() Scalar { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Negate(s.value), + } +} + +func (s *ScalarEd25519) SetBigInt(x *big.Int) (Scalar, error) { + if x == nil { + return nil, fmt.Errorf("invalid value") + } + + bi25519, _ := new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16) + var v big.Int + buf := v.Mod(x, bi25519).Bytes() + var rBuf [32]byte + for i := 0; i < len(buf) && i < 32; i++ { + rBuf[i] = buf[len(buf)-i-1] + } + value, err := edwards25519.NewScalar().SetCanonicalBytes(rBuf[:]) + if err != nil { + return nil, err + } + return &ScalarEd25519{value}, nil +} + +func (s *ScalarEd25519) BigInt() *big.Int { + var ret big.Int + buf := internal.ReverseScalarBytes(s.value.Bytes()) + return ret.SetBytes(buf) +} + +func (s *ScalarEd25519) Bytes() []byte { + return s.value.Bytes() +} + +// SetBytes takes input a 32-byte long array and returns a ed25519 scalar. +// The input must be 32-byte long and must be a reduced bytes. +func (s *ScalarEd25519) SetBytes(input []byte) (Scalar, error) { + if len(input) != 32 { + return nil, fmt.Errorf("invalid byte sequence") + } + value, err := edwards25519.NewScalar().SetCanonicalBytes(input) + if err != nil { + return nil, err + } + return &ScalarEd25519{value}, nil +} + +// SetBytesWide takes input a 64-byte long byte array, reduce it and return an ed25519 scalar. +// It uses SetUniformBytes of fillipo.io/edwards25519 - https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L85 +// If bytes is not of the right length, it returns nil and an error +func (s *ScalarEd25519) SetBytesWide(bytes []byte) (Scalar, error) { + value, err := edwards25519.NewScalar().SetUniformBytes(bytes) + if err != nil { + return nil, err + } + return &ScalarEd25519{value}, nil +} + +// SetBytesClamping uses SetBytesWithClamping of fillipo.io/edwards25519- https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L135 +// which applies the buffer pruning described in RFC 8032, Section 5.1.5 (also known as clamping) +// and sets bytes to the result. The input must be 32-byte long, and it is not modified. +// If bytes is not of the right length, SetBytesWithClamping returns nil and an error, and the receiver is unchanged. +func (s *ScalarEd25519) SetBytesClamping(bytes []byte) (Scalar, error) { + value, err := edwards25519.NewScalar().SetBytesWithClamping(bytes) + if err != nil { + return nil, err + } + return &ScalarEd25519{value}, nil +} + +// SetBytesCanonical uses SetCanonicalBytes of fillipo.io/edwards25519. +// https://github.com/FiloSottile/edwards25519/blob/v1.0.0-rc.1/scalar.go#L98 +// This function takes an input x and sets s = x, where x is a 32-byte little-endian +// encoding of s, then it returns the corresponding ed25519 scalar. If the input is +// not a canonical encoding of s, it returns nil and an error. +func (s *ScalarEd25519) SetBytesCanonical(bytes []byte) (Scalar, error) { + return s.SetBytes(bytes) +} + +func (s *ScalarEd25519) Point() Point { + return new(PointEd25519).Identity() +} + +func (s *ScalarEd25519) Clone() Scalar { + return &ScalarEd25519{ + value: edwards25519.NewScalar().Set(s.value), + } +} + +func (s *ScalarEd25519) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarEd25519) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarEd25519) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarEd25519) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarEd25519) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarEd25519) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarEd25519) GetEdwardsScalar() *edwards25519.Scalar { + return edwards25519.NewScalar().Set(s.value) +} + +func (s *ScalarEd25519) SetEdwardsScalar(sc *edwards25519.Scalar) *ScalarEd25519 { + return &ScalarEd25519{value: edwards25519.NewScalar().Set(sc)} +} + +func (s *ScalarEd25519) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarEd25519) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarEd25519) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +func (p *PointEd25519) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointEd25519) Hash(bytes []byte) Point { + /// Perform hashing to the group using the Elligator2 map + /// + /// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#section-6.7.1 + h := sha512.Sum512(bytes) + var res [32]byte + copy(res[:], h[:32]) + signBit := (res[31] & 0x80) >> 7 + + fe := new(ed.FieldElement).SetBytes(&res).BytesInto(&res) + m1 := elligatorEncode(fe) + + return toEdwards(m1, signBit) +} + +func (p *PointEd25519) Identity() Point { + return &PointEd25519{ + value: edwards25519.NewIdentityPoint(), + } +} + +func (p *PointEd25519) Generator() Point { + return &PointEd25519{ + value: edwards25519.NewGeneratorPoint(), + } +} + +func (p *PointEd25519) IsIdentity() bool { + return p.Equal(p.Identity()) +} + +func (p *PointEd25519) IsNegative() bool { + // Negative points don't really exist in ed25519 + return false +} + +func (p *PointEd25519) IsOnCurve() bool { + _, err := edwards25519.NewIdentityPoint().SetBytes(p.ToAffineCompressed()) + return err == nil +} + +func (p *PointEd25519) Double() Point { + return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, p.value)} +} + +func (p *PointEd25519) Scalar() Scalar { + return new(ScalarEd25519).Zero() +} + +func (p *PointEd25519) Neg() Point { + return &PointEd25519{value: edwards25519.NewIdentityPoint().Negate(p.value)} +} + +func (p *PointEd25519) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointEd25519) + if ok { + return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, r.value)} + } else { + return nil + } +} + +func (p *PointEd25519) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointEd25519) + if ok { + rTmp := edwards25519.NewIdentityPoint().Negate(r.value) + return &PointEd25519{value: edwards25519.NewIdentityPoint().Add(p.value, rTmp)} + } else { + return nil + } +} + +func (p *PointEd25519) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarEd25519) + if ok { + value := edwards25519.NewIdentityPoint().ScalarMult(r.value, p.value) + return &PointEd25519{value} + } else { + return nil + } +} + +// MangleScalarBitsAndMulByBasepointToProducePublicKey +// is a function for mangling the bits of a (formerly +// mathematically well-defined) "scalar" and multiplying it to produce a +// public key. +func (p *PointEd25519) MangleScalarBitsAndMulByBasepointToProducePublicKey(rhs *ScalarEd25519) *PointEd25519 { + data := rhs.value.Bytes() + s, err := edwards25519.NewScalar().SetBytesWithClamping(data[:]) + if err != nil { + return nil + } + value := edwards25519.NewIdentityPoint().ScalarBaseMult(s) + return &PointEd25519{value} +} + +func (p *PointEd25519) Equal(rhs Point) bool { + r, ok := rhs.(*PointEd25519) + if ok { + // We would like to check that the point (X/Z, Y/Z) is equal to + // the point (X'/Z', Y'/Z') without converting into affine + // coordinates (x, y) and (x', y'), which requires two inversions. + // We have that X = xZ and X' = x'Z'. Thus, x = x' is equivalent to + // (xZ)Z' = (x'Z')Z, and similarly for the y-coordinate. + return p.value.Equal(r.value) == 1 + //lhs1 := new(ed.FieldElement).Mul(&p.value.X, &r.value.Z) + //rhs1 := new(ed.FieldElement).Mul(&r.value.X, &p.value.Z) + //lhs2 := new(ed.FieldElement).Mul(&p.value.Y, &r.value.Z) + //rhs2 := new(ed.FieldElement).Mul(&r.value.Y, &p.value.Z) + // + //return lhs1.Equals(rhs1) && lhs2.Equals(rhs2) + } else { + return false + } +} + +func (p *PointEd25519) Set(x, y *big.Int) (Point, error) { + // check is identity + xx := subtle.ConstantTimeCompare(x.Bytes(), []byte{}) + yy := subtle.ConstantTimeCompare(y.Bytes(), []byte{}) + if (xx | yy) == 1 { + return p.Identity(), nil + } + xElem := new(ed.FieldElement).SetBigInt(x) + yElem := new(ed.FieldElement).SetBigInt(y) + + var data [32]byte + var affine [64]byte + xElem.BytesInto(&data) + copy(affine[:32], data[:]) + yElem.BytesInto(&data) + copy(affine[32:], data[:]) + return p.FromAffineUncompressed(affine[:]) +} + +// sqrtRatio sets r to the non-negative square root of the ratio of u and v. +// +// If u/v is square, sqrtRatio returns r and 1. If u/v is not square, SqrtRatio +// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00, +// and returns r and 0. +func sqrtRatio(u, v *ed.FieldElement) (r *ed.FieldElement, wasSquare bool) { + var sqrtM1 = ed.FieldElement{ + 533094393274173, 2016890930128738, 18285341111199, + 134597186663265, 1486323764102114, + } + a := new(ed.FieldElement) + b := new(ed.FieldElement) + r = new(ed.FieldElement) + + // r = (u * v3) * (u * v7)^((p-5)/8) + v2 := a.Square(v) + uv3 := b.Mul(u, b.Mul(v2, v)) + uv7 := a.Mul(uv3, a.Square(v2)) + r.Mul(uv3, r.Exp22523(uv7)) + + check := a.Mul(v, a.Square(r)) // check = v * r^2 + + uNeg := b.Neg(u) + correctSignSqrt := check.Equals(u) + flippedSignSqrt := check.Equals(uNeg) + flippedSignSqrtI := check.Equals(uNeg.Mul(uNeg, &sqrtM1)) + + rPrime := b.Mul(r, &sqrtM1) // r_prime = SQRT_M1 * r + // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r) + cselect(r, rPrime, r, flippedSignSqrt || flippedSignSqrtI) + + r.Abs(r) // Choose the nonnegative square root. + return r, correctSignSqrt || flippedSignSqrt +} + +// cselect sets v to a if cond == 1, and to b if cond == 0. +func cselect(v, a, b *ed.FieldElement, cond bool) *ed.FieldElement { + const mask64Bits uint64 = (1 << 64) - 1 + + m := uint64(0) + if cond { + m = mask64Bits + } + + v[0] = (m & a[0]) | (^m & b[0]) + v[1] = (m & a[1]) | (^m & b[1]) + v[2] = (m & a[2]) | (^m & b[2]) + v[3] = (m & a[3]) | (^m & b[3]) + v[4] = (m & a[4]) | (^m & b[4]) + return v +} + +func (p *PointEd25519) ToAffineCompressed() []byte { + return p.value.Bytes() +} + +func (p *PointEd25519) ToAffineUncompressed() []byte { + x, y, z, _ := p.value.ExtendedCoordinates() + recip := new(field.Element).Invert(z) + x.Multiply(x, recip) + y.Multiply(y, recip) + var out [64]byte + copy(out[:32], x.Bytes()) + copy(out[32:], y.Bytes()) + return out[:] +} + +func (p *PointEd25519) FromAffineCompressed(inBytes []byte) (Point, error) { + pt, err := edwards25519.NewIdentityPoint().SetBytes(inBytes) + if err != nil { + return nil, err + } + return &PointEd25519{value: pt}, nil +} + +func (p *PointEd25519) FromAffineUncompressed(inBytes []byte) (Point, error) { + if len(inBytes) != 64 { + return nil, fmt.Errorf("invalid byte sequence") + } + if bytes.Equal(inBytes, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) { + return &PointEd25519{value: edwards25519.NewIdentityPoint()}, nil + } + x, err := new(field.Element).SetBytes(inBytes[:32]) + if err != nil { + return nil, err + } + y, err := new(field.Element).SetBytes(inBytes[32:]) + if err != nil { + return nil, err + } + z := new(field.Element).One() + t := new(field.Element).Multiply(x, y) + value, err := edwards25519.NewIdentityPoint().SetExtendedCoordinates(x, y, z, t) + if err != nil { + return nil, err + } + return &PointEd25519{value}, nil +} + +func (p *PointEd25519) CurveName() string { + return ED25519Name +} + +func (p *PointEd25519) SumOfProducts(points []Point, scalars []Scalar) Point { + nScalars := make([]*edwards25519.Scalar, len(scalars)) + nPoints := make([]*edwards25519.Point, len(points)) + for i, sc := range scalars { + s, err := edwards25519.NewScalar().SetCanonicalBytes(sc.Bytes()) + if err != nil { + return nil + } + nScalars[i] = s + } + for i, pt := range points { + pp, ok := pt.(*PointEd25519) + if !ok { + return nil + } + nPoints[i] = pp.value + } + pt := edwards25519.NewIdentityPoint().MultiScalarMult(nScalars, nPoints) + return &PointEd25519{value: pt} +} + +func (p *PointEd25519) VarTimeDoubleScalarBaseMult(a Scalar, A Point, b Scalar) Point { + AA, ok := A.(*PointEd25519) + if !ok { + return nil + } + aa, ok := a.(*ScalarEd25519) + if !ok { + return nil + } + bb, ok := b.(*ScalarEd25519) + if !ok { + return nil + } + value := edwards25519.NewIdentityPoint().VarTimeDoubleScalarBaseMult(aa.value, AA.value, bb.value) + return &PointEd25519{value} +} + +func (p *PointEd25519) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointEd25519) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointEd25519) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointEd25519) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointEd25519) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointEd25519) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointEd25519) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointEd25519) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointEd25519) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} + +func (p *PointEd25519) GetEdwardsPoint() *edwards25519.Point { + return edwards25519.NewIdentityPoint().Set(p.value) +} + +func (p *PointEd25519) SetEdwardsPoint(pt *edwards25519.Point) *PointEd25519 { + return &PointEd25519{value: edwards25519.NewIdentityPoint().Set(pt)} +} + +// Attempt to convert to an `EdwardsPoint`, using the supplied +// choice of sign for the `EdwardsPoint`. +// * `sign`: a `u8` donating the desired sign of the resulting +// `EdwardsPoint`. `0` denotes positive and `1` negative. +func toEdwards(u *ed.FieldElement, sign byte) *PointEd25519 { + one := new(ed.FieldElement).SetOne() + // To decompress the Montgomery u coordinate to an + // `EdwardsPoint`, we apply the birational map to obtain the + // Edwards y coordinate, then do Edwards decompression. + // + // The birational map is y = (u-1)/(u+1). + // + // The exceptional points are the zeros of the denominator, + // i.e., u = -1. + // + // But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660. + // + // Since this is nonsquare mod p, u = -1 corresponds to a point + // on the twist, not the curve, so we can reject it early. + if u.Equals(new(ed.FieldElement).Neg(one)) { + return nil + } + + // y = (u-1)/(u+1) + yLhs := new(ed.FieldElement).Sub(u, one) + yRhs := new(ed.FieldElement).Add(u, one) + yInv := new(ed.FieldElement).Inverse(yRhs) + y := new(ed.FieldElement).Mul(yLhs, yInv) + yBytes := y.Bytes() + yBytes[31] ^= sign << 7 + + pt, err := edwards25519.NewIdentityPoint().SetBytes(yBytes[:]) + if err != nil { + return nil + } + pt.MultByCofactor(pt) + return &PointEd25519{value: pt} +} + +// Perform the Elligator2 mapping to a Montgomery point encoded as a 32 byte value +// +// See +func elligatorEncode(r0 *ed.FieldElement) *ed.FieldElement { + montgomeryA := &ed.FieldElement{ + 486662, 0, 0, 0, 0, + } + // montgomeryANeg is equal to -486662. + montgomeryANeg := &ed.FieldElement{2251799813198567, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247} + t := new(ed.FieldElement) + one := new(ed.FieldElement).SetOne() + // 2r^2 + d1 := new(ed.FieldElement).Add(one, t.DoubledSquare(r0)) + // A/(1+2r^2) + d := new(ed.FieldElement).Mul(montgomeryANeg, t.Inverse(d1)) + dsq := new(ed.FieldElement).Square(d) + au := new(ed.FieldElement).Mul(montgomeryA, d) + + inner := new(ed.FieldElement).Add(dsq, au) + inner.Add(inner, one) + + // d^3 + Ad^2 + d + eps := new(ed.FieldElement).Mul(d, inner) + _, wasSquare := sqrtRatio(eps, one) + + zero := new(ed.FieldElement).SetZero() + aTemp := new(ed.FieldElement).SetZero() + // 0 or A if non-square + cselect(aTemp, zero, montgomeryA, wasSquare) + // d, or d+A if non-square + u := new(ed.FieldElement).Add(d, aTemp) + // d or -d-A if non-square + cselect(u, u, new(ed.FieldElement).Neg(u), wasSquare) + return u +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/field.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/field.go new file mode 100644 index 0000000000..e3a9f5f400 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/field.go @@ -0,0 +1,280 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Package curves: Field implementation IS NOT constant time as it leverages math/big for big number operations. +package curves + +import ( + "crypto/rand" + "encoding/json" + "fmt" + "io" + "math/big" + "sync" +) + +var ed25519SubGroupOrderOnce sync.Once +var ed25519SubGroupOrder *big.Int + +// Field is a finite field. +type Field struct { + *big.Int +} + +// Element is a group element within a finite field. +type Element struct { + Modulus *Field `json:"modulus"` + Value *big.Int `json:"value"` +} + +// ElementJSON is used in JSON<>Element conversions. +// For years, big.Int hasn't properly supported JSON unmarshaling +// https://github.com/golang/go/issues/28154 +type ElementJSON struct { + Modulus string `json:"modulus"` + Value string `json:"value"` +} + +// Marshal Element to JSON +func (x *Element) MarshalJSON() ([]byte, error) { + return json.Marshal(ElementJSON{ + Modulus: x.Modulus.String(), + Value: x.Value.String(), + }) +} + +func (x *Element) UnmarshalJSON(bytes []byte) error { + var e ElementJSON + err := json.Unmarshal(bytes, &e) + if err != nil { + return err + } + // Convert the strings to big.Ints + modulus, ok := new(big.Int).SetString(e.Modulus, 10) + if !ok { + return fmt.Errorf("failed to unmarshal modulus string '%v' to big.Int", e.Modulus) + } + x.Modulus = &Field{modulus} + x.Value, ok = new(big.Int).SetString(e.Value, 10) + if !ok { + return fmt.Errorf("failed to unmarshal value string '%v' to big.Int", e.Value) + } + return nil +} + +// The probability of returning true for a randomly chosen +// non-prime is at most ¼ⁿ. 64 is a widely used standard +// that is more than sufficient. +const millerRabinRounds = 64 + +// New is a constructor for a Field. +func NewField(modulus *big.Int) *Field { + // For our purposes we never expect to be dealing with a non-prime field. This provides some protection against + // accidentally doing that. + if !modulus.ProbablyPrime(millerRabinRounds) { + panic(fmt.Sprintf("modulus: %x is not a prime", modulus)) + } + + return &Field{modulus} +} + +func newElement(field *Field, value *big.Int) *Element { + if !field.IsValid(value) { + panic(fmt.Sprintf("value: %x is not within field: %x", value, field)) + } + + return &Element{field, value} +} + +// IsValid returns whether or not the value is within [0, modulus) +func (f Field) IsValid(value *big.Int) bool { + // value < modulus && value >= 0 + return value.Cmp(f.Int) < 0 && value.Sign() >= 0 +} + +func (f Field) NewElement(value *big.Int) *Element { + return newElement(&f, value) +} + +func (f Field) Zero() *Element { + return newElement(&f, big.NewInt(0)) +} + +func (f Field) One() *Element { + return newElement(&f, big.NewInt(1)) +} + +func (f Field) RandomElement(r io.Reader) (*Element, error) { + if r == nil { + r = rand.Reader + } + var randInt *big.Int + var err error + // Ed25519 needs to do special handling + // in case the value is used in + // Scalar multiplications with points + if f.Int.Cmp(Ed25519Order()) == 0 { + scalar := NewEd25519Scalar() + randInt, err = scalar.RandomWithReader(r) + } else { + // Read a random integer within the field. This is defined as [0, max) so we don't need to + // explicitly check it is within the field. If it is not, NewElement will panic anyways. + randInt, err = rand.Int(r, f.Int) + } + if err != nil { + return nil, err + } + return newElement(&f, randInt), nil +} + +// ElementFromBytes initializes a new field element from big-endian bytes +func (f Field) ElementFromBytes(bytes []byte) *Element { + return newElement(&f, new(big.Int).SetBytes(bytes)) +} + +// ReducedElementFromBytes initializes a new field element from big-endian bytes and reduces it by +// the modulus of the field. +// +// WARNING: If this is used with cryptographic constructions which rely on a uniform distribution of +// values, this may introduce a bias to the value of the returned field element. This happens when +// the integer range of the provided bytes is not an integer multiple of the field order. +// +// Assume we are working in field which a modulus of 3 and the range of the uniform random bytes we +// provide as input is 5. Thus, the set of field elements is {0, 1, 2} and the set of integer values +// for the input bytes is: {0, 1, 2, 3, 4}. What is the distribution of the output values produced +// by this function? +// +// ReducedElementFromBytes(0) => 0 +// ReducedElementFromBytes(1) => 1 +// ReducedElementFromBytes(2) => 2 +// ReducedElementFromBytes(3) => 0 +// ReducedElementFromBytes(4) => 1 +// +// For a value space V and random value v, a uniform distribution is defined as P[V = v] = 1/|V| +// where |V| is to the order of the field. Using the results from above, we see that P[v = 0] = 2/5, +// P[v = 1] = 2/5, and P[v = 2] = 1/5. For a uniform distribution we would expect these to each be +// equal to 1/3. As they do not, this does not return uniform output for that example. +// +// To see why this is okay if the range is a multiple of the field order, change the input range to +// 6 and notice that now each output has a probability of 2/6 = 1/3, and the output is uniform. +func (f Field) ReducedElementFromBytes(bytes []byte) *Element { + value := new(big.Int).SetBytes(bytes) + value.Mod(value, f.Int) + return newElement(&f, value) +} + +func (x Element) Field() *Field { + return x.Modulus +} + +// Add returns the sum x+y +func (x Element) Add(y *Element) *Element { + x.validateFields(y) + + sum := new(big.Int).Add(x.Value, y.Value) + sum.Mod(sum, x.Modulus.Int) + return newElement(x.Modulus, sum) +} + +// Sub returns the difference x-y +func (x Element) Sub(y *Element) *Element { + x.validateFields(y) + + difference := new(big.Int).Sub(x.Value, y.Value) + difference.Mod(difference, x.Modulus.Int) + return newElement(x.Modulus, difference) +} + +// Neg returns the field negation +func (x Element) Neg() *Element { + z := new(big.Int).Neg(x.Value) + z.Mod(z, x.Modulus.Int) + return newElement(x.Modulus, z) +} + +// Mul returns the product x*y +func (x Element) Mul(y *Element) *Element { + x.validateFields(y) + + product := new(big.Int).Mul(x.Value, y.Value) + product.Mod(product, x.Modulus.Int) + return newElement(x.Modulus, product) +} + +// Div returns the quotient x/y +func (x Element) Div(y *Element) *Element { + x.validateFields(y) + + yInv := new(big.Int).ModInverse(y.Value, x.Modulus.Int) + quotient := new(big.Int).Mul(x.Value, yInv) + quotient.Mod(quotient, x.Modulus.Int) + return newElement(x.Modulus, quotient) +} + +// Pow computes x^y reduced by the modulus +func (x Element) Pow(y *Element) *Element { + x.validateFields(y) + + return newElement(x.Modulus, new(big.Int).Exp(x.Value, y.Value, x.Modulus.Int)) +} + +func (x Element) Invert() *Element { + return newElement(x.Modulus, new(big.Int).ModInverse(x.Value, x.Modulus.Int)) +} + +func (x Element) Sqrt() *Element { + return newElement(x.Modulus, new(big.Int).ModSqrt(x.Value, x.Modulus.Int)) +} + +// BigInt returns value as a big.Int +func (x Element) BigInt() *big.Int { + return x.Value +} + +// Bytes returns the value as bytes +func (x Element) Bytes() []byte { + return x.BigInt().Bytes() +} + +// IsEqual returns x == y +func (x Element) IsEqual(y *Element) bool { + if !x.isEqualFields(y) { + return false + } + + return x.Value.Cmp(y.Value) == 0 +} + +// Clone returns a new copy of the element +func (x Element) Clone() *Element { + return x.Modulus.ElementFromBytes(x.Bytes()) +} + +func (x Element) isEqualFields(y *Element) bool { + return x.Modulus.Int.Cmp(y.Modulus.Int) == 0 +} + +func (x Element) validateFields(y *Element) { + if !x.isEqualFields(y) { + panic("fields must match for valid binary operation") + } +} + +// SubgroupOrder returns the order of the Ed25519 base Point. +func Ed25519Order() *big.Int { + ed25519SubGroupOrderOnce.Do(func() { + order, ok := new(big.Int).SetString( + "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + 16, + ) + if !ok { + panic("invalid hex string provided. This should never happen as it is constant.") + } + ed25519SubGroupOrder = order + }) + + return ed25519SubGroupOrder +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/k256_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/k256_curve.go new file mode 100644 index 0000000000..ac1a0f839d --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/k256_curve.go @@ -0,0 +1,669 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + "fmt" + "io" + "math/big" + "sync" + + "github.com/btcsuite/btcd/btcec" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + secp256k1 "github.com/coinbase/kryptology/pkg/core/curves/native/k256" + "github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp" + "github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq" +) + +var oldK256Initonce sync.Once +var oldK256 Koblitz256 + +type Koblitz256 struct { + *elliptic.CurveParams +} + +func oldK256InitAll() { + curve := btcec.S256() + oldK256.CurveParams = new(elliptic.CurveParams) + oldK256.P = curve.P + oldK256.N = curve.N + oldK256.Gx = curve.Gx + oldK256.Gy = curve.Gy + oldK256.B = curve.B + oldK256.BitSize = curve.BitSize + oldK256.Name = K256Name +} + +func K256Curve() *Koblitz256 { + oldK256Initonce.Do(oldK256InitAll) + return &oldK256 +} + +func (curve *Koblitz256) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +func (curve *Koblitz256) IsOnCurve(x, y *big.Int) bool { + _, err := secp256k1.K256PointNew().SetBigInt(x, y) + return err == nil +} + +func (curve *Koblitz256) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + p1, err := secp256k1.K256PointNew().SetBigInt(x1, y1) + if err != nil { + return nil, nil + } + p2, err := secp256k1.K256PointNew().SetBigInt(x2, y2) + if err != nil { + return nil, nil + } + return p1.Add(p1, p2).BigInt() +} + +func (curve *Koblitz256) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + p1, err := secp256k1.K256PointNew().SetBigInt(x1, y1) + if err != nil { + return nil, nil + } + return p1.Double(p1).BigInt() +} + +func (curve *Koblitz256) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + p1, err := secp256k1.K256PointNew().SetBigInt(Bx, By) + if err != nil { + return nil, nil + } + var bytes [32]byte + copy(bytes[:], internal.ReverseScalarBytes(k)) + s, err := fq.K256FqNew().SetBytes(&bytes) + if err != nil { + return nil, nil + } + return p1.Mul(p1, s).BigInt() +} + +func (curve *Koblitz256) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + var bytes [32]byte + copy(bytes[:], internal.ReverseScalarBytes(k)) + s, err := fq.K256FqNew().SetBytes(&bytes) + if err != nil { + return nil, nil + } + p1 := secp256k1.K256PointNew().Generator() + return p1.Mul(p1, s).BigInt() +} + +type ScalarK256 struct { + value *native.Field +} + +type PointK256 struct { + value *native.EllipticPoint +} + +func (s *ScalarK256) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarK256) Hash(bytes []byte) Scalar { + dst := []byte("secp256k1_XMD:SHA-256_SSWU_RO_") + xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), bytes, dst, 48) + var t [64]byte + copy(t[:48], internal.ReverseScalarBytes(xmd)) + + return &ScalarK256{ + value: fq.K256FqNew().SetBytesWide(&t), + } +} + +func (s *ScalarK256) Zero() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().SetZero(), + } +} + +func (s *ScalarK256) One() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().SetOne(), + } +} + +func (s *ScalarK256) IsZero() bool { + return s.value.IsZero() == 1 +} + +func (s *ScalarK256) IsOne() bool { + return s.value.IsOne() == 1 +} + +func (s *ScalarK256) IsOdd() bool { + return s.value.Bytes()[0]&1 == 1 +} + +func (s *ScalarK256) IsEven() bool { + return s.value.Bytes()[0]&1 == 0 +} + +func (s *ScalarK256) New(value int) Scalar { + t := fq.K256FqNew() + v := big.NewInt(int64(value)) + if value < 0 { + v.Mod(v, t.Params.BiModulus) + } + return &ScalarK256{ + value: t.SetBigInt(v), + } +} + +func (s *ScalarK256) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarK256) + if ok { + return s.value.Cmp(r.value) + } else { + return -2 + } +} + +func (s *ScalarK256) Square() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().Square(s.value), + } +} + +func (s *ScalarK256) Double() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().Double(s.value), + } +} + +func (s *ScalarK256) Invert() (Scalar, error) { + value, wasInverted := fq.K256FqNew().Invert(s.value) + if !wasInverted { + return nil, fmt.Errorf("inverse doesn't exist") + } + return &ScalarK256{ + value, + }, nil +} + +func (s *ScalarK256) Sqrt() (Scalar, error) { + value, wasSquare := fq.K256FqNew().Sqrt(s.value) + if !wasSquare { + return nil, fmt.Errorf("not a square") + } + return &ScalarK256{ + value, + }, nil +} + +func (s *ScalarK256) Cube() Scalar { + value := fq.K256FqNew().Mul(s.value, s.value) + value.Mul(value, s.value) + return &ScalarK256{ + value, + } +} + +func (s *ScalarK256) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarK256) + if ok { + return &ScalarK256{ + value: fq.K256FqNew().Add(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarK256) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarK256) + if ok { + return &ScalarK256{ + value: fq.K256FqNew().Sub(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarK256) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarK256) + if ok { + return &ScalarK256{ + value: fq.K256FqNew().Mul(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarK256) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarK256) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarK256) + if ok { + v, wasInverted := fq.K256FqNew().Invert(r.value) + if !wasInverted { + return nil + } + v.Mul(v, s.value) + return &ScalarK256{value: v} + } else { + return nil + } +} + +func (s *ScalarK256) Neg() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().Neg(s.value), + } +} + +func (s *ScalarK256) SetBigInt(v *big.Int) (Scalar, error) { + if v == nil { + return nil, fmt.Errorf("'v' cannot be nil") + } + value := fq.K256FqNew().SetBigInt(v) + return &ScalarK256{ + value, + }, nil +} + +func (s *ScalarK256) BigInt() *big.Int { + return s.value.BigInt() +} + +func (s *ScalarK256) Bytes() []byte { + t := s.value.Bytes() + return internal.ReverseScalarBytes(t[:]) +} + +func (s *ScalarK256) SetBytes(bytes []byte) (Scalar, error) { + if len(bytes) != 32 { + return nil, fmt.Errorf("invalid length") + } + var seq [32]byte + copy(seq[:], internal.ReverseScalarBytes(bytes)) + value, err := fq.K256FqNew().SetBytes(&seq) + if err != nil { + return nil, err + } + return &ScalarK256{ + value, + }, nil +} + +func (s *ScalarK256) SetBytesWide(bytes []byte) (Scalar, error) { + if len(bytes) != 64 { + return nil, fmt.Errorf("invalid length") + } + var seq [64]byte + copy(seq[:], bytes) + return &ScalarK256{ + value: fq.K256FqNew().SetBytesWide(&seq), + }, nil +} + +func (s *ScalarK256) Point() Point { + return new(PointK256).Identity() +} + +func (s *ScalarK256) Clone() Scalar { + return &ScalarK256{ + value: fq.K256FqNew().Set(s.value), + } +} + +func (s *ScalarK256) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarK256) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarK256) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarK256) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarK256) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarK256) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarK256) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarK256) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarK256) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +func (p *PointK256) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointK256) Hash(bytes []byte) Point { + value, err := secp256k1.K256PointNew().Hash(bytes, native.EllipticPointHasherSha256()) + + // TODO: change hash to return an error also + if err != nil { + return nil + } + + return &PointK256{value} +} + +func (p *PointK256) Identity() Point { + return &PointK256{ + value: secp256k1.K256PointNew().Identity(), + } +} + +func (p *PointK256) Generator() Point { + return &PointK256{ + value: secp256k1.K256PointNew().Generator(), + } +} + +func (p *PointK256) IsIdentity() bool { + return p.value.IsIdentity() +} + +func (p *PointK256) IsNegative() bool { + return p.value.GetY().Value[0]&1 == 1 +} + +func (p *PointK256) IsOnCurve() bool { + return p.value.IsOnCurve() +} + +func (p *PointK256) Double() Point { + value := secp256k1.K256PointNew().Double(p.value) + return &PointK256{value} +} + +func (p *PointK256) Scalar() Scalar { + return new(ScalarK256).Zero() +} + +func (p *PointK256) Neg() Point { + value := secp256k1.K256PointNew().Neg(p.value) + return &PointK256{value} +} + +func (p *PointK256) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointK256) + if ok { + value := secp256k1.K256PointNew().Add(p.value, r.value) + return &PointK256{value} + } else { + return nil + } +} + +func (p *PointK256) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointK256) + if ok { + value := secp256k1.K256PointNew().Sub(p.value, r.value) + return &PointK256{value} + } else { + return nil + } +} + +func (p *PointK256) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarK256) + if ok { + value := secp256k1.K256PointNew().Mul(p.value, r.value) + return &PointK256{value} + } else { + return nil + } +} + +func (p *PointK256) Equal(rhs Point) bool { + r, ok := rhs.(*PointK256) + if ok { + return p.value.Equal(r.value) == 1 + } else { + return false + } +} + +func (p *PointK256) Set(x, y *big.Int) (Point, error) { + value, err := secp256k1.K256PointNew().SetBigInt(x, y) + if err != nil { + return nil, err + } + return &PointK256{value}, nil +} + +func (p *PointK256) ToAffineCompressed() []byte { + var x [33]byte + x[0] = byte(2) + + t := secp256k1.K256PointNew().ToAffine(p.value) + + x[0] |= t.Y.Bytes()[0] & 1 + + xBytes := t.X.Bytes() + copy(x[1:], internal.ReverseScalarBytes(xBytes[:])) + return x[:] +} + +func (p *PointK256) ToAffineUncompressed() []byte { + var out [65]byte + out[0] = byte(4) + t := secp256k1.K256PointNew().ToAffine(p.value) + arr := t.X.Bytes() + copy(out[1:33], internal.ReverseScalarBytes(arr[:])) + arr = t.Y.Bytes() + copy(out[33:], internal.ReverseScalarBytes(arr[:])) + return out[:] +} + +func (p *PointK256) FromAffineCompressed(bytes []byte) (Point, error) { + var raw [native.FieldBytes]byte + if len(bytes) != 33 { + return nil, fmt.Errorf("invalid byte sequence") + } + sign := int(bytes[0]) + if sign != 2 && sign != 3 { + return nil, fmt.Errorf("invalid sign byte") + } + sign &= 0x1 + + copy(raw[:], internal.ReverseScalarBytes(bytes[1:])) + x, err := fp.K256FpNew().SetBytes(&raw) + if err != nil { + return nil, err + } + + value := secp256k1.K256PointNew().Identity() + rhs := fp.K256FpNew() + p.value.Arithmetic.RhsEq(rhs, x) + // test that rhs is quadratic residue + // if not, then this Point is at infinity + y, wasQr := fp.K256FpNew().Sqrt(rhs) + if wasQr { + // fix the sign + sigY := int(y.Bytes()[0] & 1) + if sigY != sign { + y.Neg(y) + } + value.X = x + value.Y = y + value.Z.SetOne() + } + return &PointK256{value}, nil +} + +func (p *PointK256) FromAffineUncompressed(bytes []byte) (Point, error) { + var arr [native.FieldBytes]byte + if len(bytes) != 65 { + return nil, fmt.Errorf("invalid byte sequence") + } + if bytes[0] != 4 { + return nil, fmt.Errorf("invalid sign byte") + } + + copy(arr[:], internal.ReverseScalarBytes(bytes[1:33])) + x, err := fp.K256FpNew().SetBytes(&arr) + if err != nil { + return nil, err + } + copy(arr[:], internal.ReverseScalarBytes(bytes[33:])) + y, err := fp.K256FpNew().SetBytes(&arr) + if err != nil { + return nil, err + } + value := secp256k1.K256PointNew() + value.X = x + value.Y = y + value.Z.SetOne() + return &PointK256{value}, nil +} + +func (p *PointK256) CurveName() string { + return p.value.Params.Name +} + +func (p *PointK256) SumOfProducts(points []Point, scalars []Scalar) Point { + nPoints := make([]*native.EllipticPoint, len(points)) + nScalars := make([]*native.Field, len(scalars)) + for i, pt := range points { + ptv, ok := pt.(*PointK256) + if !ok { + return nil + } + nPoints[i] = ptv.value + } + for i, sc := range scalars { + s, ok := sc.(*ScalarK256) + if !ok { + return nil + } + nScalars[i] = s.value + } + value := secp256k1.K256PointNew() + _, err := value.SumOfProducts(nPoints, nScalars) + if err != nil { + return nil + } + return &PointK256{value} +} + +func (p *PointK256) X() *native.Field { + return p.value.GetX() +} + +func (p *PointK256) Y() *native.Field { + return p.value.GetY() +} + +func (p *PointK256) Params() *elliptic.CurveParams { + return K256Curve().Params() +} + +func (p *PointK256) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointK256) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointK256) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointK256) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointK256) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointK256) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointK256) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointK256) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointK256) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/bls12381.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/bls12381.go new file mode 100644 index 0000000000..82e490d514 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/bls12381.go @@ -0,0 +1,48 @@ +package bls12381 + +import ( + "math/bits" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var fqModulusBytes = [native.FieldBytes]byte{0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7, 0xed, 0x73} + +const ( + // The BLS parameter x for BLS12-381 is -0xd201000000010000 + paramX = uint64(0xd201000000010000) + Limbs = 6 + FieldBytes = 48 + WideFieldBytes = 96 + DoubleWideFieldBytes = 192 +) + +// mac Multiply and Accumulate - compute a + (b * c) + d, return the result and new carry +func mac(a, b, c, d uint64) (uint64, uint64) { + hi, lo := bits.Mul64(b, c) + carry2, carry := bits.Add64(a, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, carry2, 0) + hi, _ = bits.Add64(hi, 0, carry) + + return lo, hi +} + +// adc Add w/Carry +func adc(x, y, carry uint64) (uint64, uint64) { + sum := x + y + carry + // The sum will overflow if both top bits are set (x & y) or if one of them + // is (x | y), and a carry from the lower place happened. If such a carry + // happens, the top bit will be 1 + 0 + 1 = 0 (&^ sum). + carryOut := ((x & y) | ((x | y) &^ sum)) >> 63 + carryOut |= ((x & carry) | ((x | carry) &^ sum)) >> 63 + carryOut |= ((y & carry) | ((y | carry) &^ sum)) >> 63 + return sum, carryOut +} + +// sbb Subtract with borrow +func sbb(x, y, borrow uint64) (uint64, uint64) { + diff := x - (y + borrow) + borrowOut := ((^x & y) | (^(x ^ y) & diff)) >> 63 + return diff, borrowOut +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp.go new file mode 100644 index 0000000000..090a1fdd4b --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp.go @@ -0,0 +1,694 @@ +package bls12381 + +import ( + "encoding/binary" + "fmt" + "io" + "math/big" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +// fp field element mod p +type fp [Limbs]uint64 + +var ( + modulus = fp{ + 0xb9feffffffffaaab, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + } + halfModulus = fp{ + 0xdcff_7fff_ffff_d556, + 0x0f55_ffff_58a9_ffff, + 0xb398_6950_7b58_7b12, + 0xb23b_a5c2_79c2_895f, + 0x258d_d3db_21a5_d66b, + 0x0d00_88f5_1cbf_f34d, + } + // 2^256 mod p + r = fp{ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + } + // 2^512 mod p + r2 = fp{ + 0xf4df1f341c341746, + 0x0a76e6a609d104f1, + 0x8de5476c4c95b6d5, + 0x67eb88a9939d83c0, + 0x9a793e85b519952d, + 0x11988fe592cae3aa, + } + // 2^768 mod p + r3 = fp{ + 0xed48ac6bd94ca1e0, + 0x315f831e03a7adf8, + 0x9a53352a615e29dd, + 0x34c04e5e921e1761, + 0x2512d43565724728, + 0x0aa6346091755d4d, + } + biModulus = new(big.Int).SetBytes([]byte{ + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab}, + ) +) + +// inv = -(p^{-1} mod 2^64) mod 2^64 +const inv = 0x89f3_fffc_fffc_fffd +const hashBytes = 64 + +// IsZero returns 1 if fp == 0, 0 otherwise +func (f *fp) IsZero() int { + t := f[0] + t |= f[1] + t |= f[2] + t |= f[3] + t |= f[4] + t |= f[5] + return int(((int64(t) | int64(-t)) >> 63) + 1) +} + +// IsNonZero returns 1 if fp != 0, 0 otherwise +func (f *fp) IsNonZero() int { + t := f[0] + t |= f[1] + t |= f[2] + t |= f[3] + t |= f[4] + t |= f[5] + return int(-((int64(t) | int64(-t)) >> 63)) +} + +// IsOne returns 1 if fp == 1, 0 otherwise +func (f *fp) IsOne() int { + return f.Equal(&r) +} + +// Cmp returns -1 if f < rhs +// 0 if f == rhs +// 1 if f > rhs +func (f *fp) Cmp(rhs *fp) int { + gt := uint64(0) + lt := uint64(0) + for i := 5; i >= 0; i-- { + // convert to two 64-bit numbers where + // the leading bits are zeros and hold no meaning + // so rhs - f actually means gt + // and f - rhs actually means lt. + rhsH := rhs[i] >> 32 + rhsL := rhs[i] & 0xffffffff + lhsH := f[i] >> 32 + lhsL := f[i] & 0xffffffff + + // Check the leading bit + // if negative then f > rhs + // if positive then f < rhs + gt |= (rhsH - lhsH) >> 32 & 1 &^ lt + lt |= (lhsH - rhsH) >> 32 & 1 &^ gt + gt |= (rhsL - lhsL) >> 32 & 1 &^ lt + lt |= (lhsL - rhsL) >> 32 & 1 &^ gt + } + // Make the result -1 for <, 0 for =, 1 for > + return int(gt) - int(lt) +} + +// Equal returns 1 if fp == rhs, 0 otherwise +func (f *fp) Equal(rhs *fp) int { + t := f[0] ^ rhs[0] + t |= f[1] ^ rhs[1] + t |= f[2] ^ rhs[2] + t |= f[3] ^ rhs[3] + t |= f[4] ^ rhs[4] + t |= f[5] ^ rhs[5] + return int(((int64(t) | int64(-t)) >> 63) + 1) +} + +// LexicographicallyLargest returns 1 if +// this element is strictly lexicographically larger than its negation +// 0 otherwise +func (f *fp) LexicographicallyLargest() int { + var ff fp + ff.fromMontgomery(f) + + _, borrow := sbb(ff[0], halfModulus[0], 0) + _, borrow = sbb(ff[1], halfModulus[1], borrow) + _, borrow = sbb(ff[2], halfModulus[2], borrow) + _, borrow = sbb(ff[3], halfModulus[3], borrow) + _, borrow = sbb(ff[4], halfModulus[4], borrow) + _, borrow = sbb(ff[5], halfModulus[5], borrow) + + return (int(borrow) - 1) & 1 +} + +// Sgn0 returns the lowest bit value +func (f *fp) Sgn0() int { + t := new(fp).fromMontgomery(f) + return int(t[0] & 1) +} + +// SetOne fp = r +func (f *fp) SetOne() *fp { + f[0] = r[0] + f[1] = r[1] + f[2] = r[2] + f[3] = r[3] + f[4] = r[4] + f[5] = r[5] + return f +} + +// SetZero fp = 0 +func (f *fp) SetZero() *fp { + f[0] = 0 + f[1] = 0 + f[2] = 0 + f[3] = 0 + f[4] = 0 + f[5] = 0 + return f +} + +// SetUint64 fp = rhs +func (f *fp) SetUint64(rhs uint64) *fp { + f[0] = rhs + f[1] = 0 + f[2] = 0 + f[3] = 0 + f[4] = 0 + f[5] = 0 + return f.toMontgomery(f) +} + +// Random generates a random field element +func (f *fp) Random(reader io.Reader) (*fp, error) { + var t [WideFieldBytes]byte + n, err := reader.Read(t[:]) + if err != nil { + return nil, err + } + if n != WideFieldBytes { + return nil, fmt.Errorf("can only read %d when %d are needed", n, WideFieldBytes) + } + return f.Hash(t[:]), nil +} + +// Hash converts the byte sequence into a field element +func (f *fp) Hash(input []byte) *fp { + dst := []byte("BLS12381_XMD:SHA-256_SSWU_RO_") + xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), input, dst, hashBytes) + var t [WideFieldBytes]byte + copy(t[:hashBytes], internal.ReverseScalarBytes(xmd)) + return f.SetBytesWide(&t) +} + +// toMontgomery converts this field to montgomery form +func (f *fp) toMontgomery(a *fp) *fp { + // arg.R^0 * R^2 / R = arg.R + return f.Mul(a, &r2) +} + +// fromMontgomery converts this field from montgomery form +func (f *fp) fromMontgomery(a *fp) *fp { + // Mul by 1 is division by 2^256 mod q + //out.Mul(arg, &[native.FieldLimbs]uint64{1, 0, 0, 0}) + return f.montReduce(&[Limbs * 2]uint64{a[0], a[1], a[2], a[3], a[4], a[5], 0, 0, 0, 0, 0, 0}) +} + +// Neg performs modular negation +func (f *fp) Neg(a *fp) *fp { + // Subtract `arg` from `modulus`. Ignore final borrow + // since it can't underflow. + var t [Limbs]uint64 + var borrow uint64 + t[0], borrow = sbb(modulus[0], a[0], 0) + t[1], borrow = sbb(modulus[1], a[1], borrow) + t[2], borrow = sbb(modulus[2], a[2], borrow) + t[3], borrow = sbb(modulus[3], a[3], borrow) + t[4], borrow = sbb(modulus[4], a[4], borrow) + t[5], _ = sbb(modulus[5], a[5], borrow) + + // t could be `modulus` if `arg`=0. Set mask=0 if self=0 + // and 0xff..ff if `arg`!=0 + mask := a[0] | a[1] | a[2] | a[3] | a[4] | a[5] + mask = -((mask | -mask) >> 63) + f[0] = t[0] & mask + f[1] = t[1] & mask + f[2] = t[2] & mask + f[3] = t[3] & mask + f[4] = t[4] & mask + f[5] = t[5] & mask + return f +} + +// Square performs modular square +func (f *fp) Square(a *fp) *fp { + var r [2 * Limbs]uint64 + var carry uint64 + + r[1], carry = mac(0, a[0], a[1], 0) + r[2], carry = mac(0, a[0], a[2], carry) + r[3], carry = mac(0, a[0], a[3], carry) + r[4], carry = mac(0, a[0], a[4], carry) + r[5], r[6] = mac(0, a[0], a[5], carry) + + r[3], carry = mac(r[3], a[1], a[2], 0) + r[4], carry = mac(r[4], a[1], a[3], carry) + r[5], carry = mac(r[5], a[1], a[4], carry) + r[6], r[7] = mac(r[6], a[1], a[5], carry) + + r[5], carry = mac(r[5], a[2], a[3], 0) + r[6], carry = mac(r[6], a[2], a[4], carry) + r[7], r[8] = mac(r[7], a[2], a[5], carry) + + r[7], carry = mac(r[7], a[3], a[4], 0) + r[8], r[9] = mac(r[8], a[3], a[5], carry) + + r[9], r[10] = mac(r[9], a[4], a[5], 0) + + r[11] = r[10] >> 63 + r[10] = (r[10] << 1) | r[9]>>63 + r[9] = (r[9] << 1) | r[8]>>63 + r[8] = (r[8] << 1) | r[7]>>63 + r[7] = (r[7] << 1) | r[6]>>63 + r[6] = (r[6] << 1) | r[5]>>63 + r[5] = (r[5] << 1) | r[4]>>63 + r[4] = (r[4] << 1) | r[3]>>63 + r[3] = (r[3] << 1) | r[2]>>63 + r[2] = (r[2] << 1) | r[1]>>63 + r[1] = r[1] << 1 + + r[0], carry = mac(0, a[0], a[0], 0) + r[1], carry = adc(0, r[1], carry) + r[2], carry = mac(r[2], a[1], a[1], carry) + r[3], carry = adc(0, r[3], carry) + r[4], carry = mac(r[4], a[2], a[2], carry) + r[5], carry = adc(0, r[5], carry) + r[6], carry = mac(r[6], a[3], a[3], carry) + r[7], carry = adc(0, r[7], carry) + r[8], carry = mac(r[8], a[4], a[4], carry) + r[9], carry = adc(0, r[9], carry) + r[10], carry = mac(r[10], a[5], a[5], carry) + r[11], _ = adc(0, r[11], carry) + + return f.montReduce(&r) +} + +// Double this element +func (f *fp) Double(a *fp) *fp { + return f.Add(a, a) +} + +// Mul performs modular multiplication +func (f *fp) Mul(arg1, arg2 *fp) *fp { + // Schoolbook multiplication + var r [2 * Limbs]uint64 + var carry uint64 + + r[0], carry = mac(0, arg1[0], arg2[0], 0) + r[1], carry = mac(0, arg1[0], arg2[1], carry) + r[2], carry = mac(0, arg1[0], arg2[2], carry) + r[3], carry = mac(0, arg1[0], arg2[3], carry) + r[4], carry = mac(0, arg1[0], arg2[4], carry) + r[5], r[6] = mac(0, arg1[0], arg2[5], carry) + + r[1], carry = mac(r[1], arg1[1], arg2[0], 0) + r[2], carry = mac(r[2], arg1[1], arg2[1], carry) + r[3], carry = mac(r[3], arg1[1], arg2[2], carry) + r[4], carry = mac(r[4], arg1[1], arg2[3], carry) + r[5], carry = mac(r[5], arg1[1], arg2[4], carry) + r[6], r[7] = mac(r[6], arg1[1], arg2[5], carry) + + r[2], carry = mac(r[2], arg1[2], arg2[0], 0) + r[3], carry = mac(r[3], arg1[2], arg2[1], carry) + r[4], carry = mac(r[4], arg1[2], arg2[2], carry) + r[5], carry = mac(r[5], arg1[2], arg2[3], carry) + r[6], carry = mac(r[6], arg1[2], arg2[4], carry) + r[7], r[8] = mac(r[7], arg1[2], arg2[5], carry) + + r[3], carry = mac(r[3], arg1[3], arg2[0], 0) + r[4], carry = mac(r[4], arg1[3], arg2[1], carry) + r[5], carry = mac(r[5], arg1[3], arg2[2], carry) + r[6], carry = mac(r[6], arg1[3], arg2[3], carry) + r[7], carry = mac(r[7], arg1[3], arg2[4], carry) + r[8], r[9] = mac(r[8], arg1[3], arg2[5], carry) + + r[4], carry = mac(r[4], arg1[4], arg2[0], 0) + r[5], carry = mac(r[5], arg1[4], arg2[1], carry) + r[6], carry = mac(r[6], arg1[4], arg2[2], carry) + r[7], carry = mac(r[7], arg1[4], arg2[3], carry) + r[8], carry = mac(r[8], arg1[4], arg2[4], carry) + r[9], r[10] = mac(r[9], arg1[4], arg2[5], carry) + + r[5], carry = mac(r[5], arg1[5], arg2[0], 0) + r[6], carry = mac(r[6], arg1[5], arg2[1], carry) + r[7], carry = mac(r[7], arg1[5], arg2[2], carry) + r[8], carry = mac(r[8], arg1[5], arg2[3], carry) + r[9], carry = mac(r[9], arg1[5], arg2[4], carry) + r[10], r[11] = mac(r[10], arg1[5], arg2[5], carry) + + return f.montReduce(&r) +} + +// MulBy3b returns arg * 12 or 3 * b +func (f *fp) MulBy3b(arg *fp) *fp { + var a, t fp + a.Double(arg) // 2 + t.Double(&a) // 4 + a.Double(&t) // 8 + a.Add(&a, &t) // 12 + return f.Set(&a) +} + +// Add performs modular addition +func (f *fp) Add(arg1, arg2 *fp) *fp { + var t fp + var carry uint64 + + t[0], carry = adc(arg1[0], arg2[0], 0) + t[1], carry = adc(arg1[1], arg2[1], carry) + t[2], carry = adc(arg1[2], arg2[2], carry) + t[3], carry = adc(arg1[3], arg2[3], carry) + t[4], carry = adc(arg1[4], arg2[4], carry) + t[5], _ = adc(arg1[5], arg2[5], carry) + + // Subtract the modulus to ensure the value + // is smaller. + return f.Sub(&t, &modulus) +} + +// Sub performs modular subtraction +func (f *fp) Sub(arg1, arg2 *fp) *fp { + d0, borrow := sbb(arg1[0], arg2[0], 0) + d1, borrow := sbb(arg1[1], arg2[1], borrow) + d2, borrow := sbb(arg1[2], arg2[2], borrow) + d3, borrow := sbb(arg1[3], arg2[3], borrow) + d4, borrow := sbb(arg1[4], arg2[4], borrow) + d5, borrow := sbb(arg1[5], arg2[5], borrow) + + // If underflow occurred on the final limb, borrow 0xff...ff, otherwise + // borrow = 0x00...00. Conditionally mask to add the modulus + borrow = -borrow + d0, carry := adc(d0, modulus[0]&borrow, 0) + d1, carry = adc(d1, modulus[1]&borrow, carry) + d2, carry = adc(d2, modulus[2]&borrow, carry) + d3, carry = adc(d3, modulus[3]&borrow, carry) + d4, carry = adc(d4, modulus[4]&borrow, carry) + d5, _ = adc(d5, modulus[5]&borrow, carry) + + f[0] = d0 + f[1] = d1 + f[2] = d2 + f[3] = d3 + f[4] = d4 + f[5] = d5 + return f +} + +// Sqrt performs modular square root +func (f *fp) Sqrt(a *fp) (*fp, int) { + // Shank's method, as p = 3 (mod 4). This means + // exponentiate by (p+1)/4. This only works for elements + // that are actually quadratic residue, + // so check the result at the end. + var c, z fp + z.pow(a, &fp{ + 0xee7fbfffffffeaab, + 0x07aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x0680447a8e5ff9a6, + }) + + c.Square(&z) + wasSquare := c.Equal(a) + f.CMove(f, &z, wasSquare) + return f, wasSquare +} + +// Invert performs modular inverse +func (f *fp) Invert(a *fp) (*fp, int) { + // Exponentiate by p - 2 + t := &fp{} + t.pow(a, &fp{ + 0xb9feffffffffaaa9, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a, + }) + wasInverted := a.IsNonZero() + f.CMove(a, t, wasInverted) + return f, wasInverted +} + +// SetBytes converts a little endian byte array into a field element +// return 0 if the bytes are not in the field, 1 if they are +func (f *fp) SetBytes(arg *[FieldBytes]byte) (*fp, int) { + var borrow uint64 + t := &fp{} + + t[0] = binary.LittleEndian.Uint64(arg[:8]) + t[1] = binary.LittleEndian.Uint64(arg[8:16]) + t[2] = binary.LittleEndian.Uint64(arg[16:24]) + t[3] = binary.LittleEndian.Uint64(arg[24:32]) + t[4] = binary.LittleEndian.Uint64(arg[32:40]) + t[5] = binary.LittleEndian.Uint64(arg[40:]) + + // Try to subtract the modulus + _, borrow = sbb(t[0], modulus[0], 0) + _, borrow = sbb(t[1], modulus[1], borrow) + _, borrow = sbb(t[2], modulus[2], borrow) + _, borrow = sbb(t[3], modulus[3], borrow) + _, borrow = sbb(t[4], modulus[4], borrow) + _, borrow = sbb(t[5], modulus[5], borrow) + + // If the element is smaller than modulus then the + // subtraction will underflow, producing a borrow value + // of 1. Otherwise, it'll be zero. + mask := int(borrow) + return f.CMove(f, t.toMontgomery(t), mask), mask +} + +// SetBytesWide takes 96 bytes as input and treats them as a 512-bit number. +// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/Fp.rs#L255 +// We reduce an arbitrary 768-bit number by decomposing it into two 384-bit digits +// with the higher bits multiplied by 2^384. Thus, we perform two reductions +// +// 1. the lower bits are multiplied by r^2, as normal +// 2. the upper bits are multiplied by r^2 * 2^384 = r^3 +// +// and computing their sum in the field. It remains to see that arbitrary 384-bit +// numbers can be placed into Montgomery form safely using the reduction. The +// reduction works so long as the product is less than r=2^384 multiplied by +// the modulus. This holds because for any `c` smaller than the modulus, we have +// that (2^384 - 1)*c is an acceptable product for the reduction. Therefore, the +// reduction always works so long as `c` is in the field; in this case it is either the +// constant `r2` or `r3`. +func (f *fp) SetBytesWide(a *[WideFieldBytes]byte) *fp { + d0 := &fp{ + binary.LittleEndian.Uint64(a[:8]), + binary.LittleEndian.Uint64(a[8:16]), + binary.LittleEndian.Uint64(a[16:24]), + binary.LittleEndian.Uint64(a[24:32]), + binary.LittleEndian.Uint64(a[32:40]), + binary.LittleEndian.Uint64(a[40:48]), + } + d1 := &fp{ + binary.LittleEndian.Uint64(a[48:56]), + binary.LittleEndian.Uint64(a[56:64]), + binary.LittleEndian.Uint64(a[64:72]), + binary.LittleEndian.Uint64(a[72:80]), + binary.LittleEndian.Uint64(a[80:88]), + binary.LittleEndian.Uint64(a[88:96]), + } + // d0*r2 + d1*r3 + d0.Mul(d0, &r2) + d1.Mul(d1, &r3) + return f.Add(d0, d1) +} + +// SetBigInt initializes an element from big.Int +// The value is reduced by the modulus +func (f *fp) SetBigInt(bi *big.Int) *fp { + var buffer [FieldBytes]byte + t := new(big.Int).Set(bi) + t.Mod(t, biModulus) + t.FillBytes(buffer[:]) + copy(buffer[:], internal.ReverseScalarBytes(buffer[:])) + _, _ = f.SetBytes(&buffer) + return f +} + +// Set copies a into fp +func (f *fp) Set(a *fp) *fp { + f[0] = a[0] + f[1] = a[1] + f[2] = a[2] + f[3] = a[3] + f[4] = a[4] + f[5] = a[5] + return f +} + +// SetLimbs converts an array into a field element +// by converting to montgomery form +func (f *fp) SetLimbs(a *[Limbs]uint64) *fp { + return f.toMontgomery((*fp)(a)) +} + +// SetRaw converts a raw array into a field element +// Assumes input is already in montgomery form +func (f *fp) SetRaw(a *[Limbs]uint64) *fp { + f[0] = a[0] + f[1] = a[1] + f[2] = a[2] + f[3] = a[3] + f[4] = a[4] + f[5] = a[5] + return f +} + +// Bytes converts a field element to a little endian byte array +func (f *fp) Bytes() [FieldBytes]byte { + var out [FieldBytes]byte + t := new(fp).fromMontgomery(f) + binary.LittleEndian.PutUint64(out[:8], t[0]) + binary.LittleEndian.PutUint64(out[8:16], t[1]) + binary.LittleEndian.PutUint64(out[16:24], t[2]) + binary.LittleEndian.PutUint64(out[24:32], t[3]) + binary.LittleEndian.PutUint64(out[32:40], t[4]) + binary.LittleEndian.PutUint64(out[40:], t[5]) + return out +} + +// BigInt converts this element into the big.Int struct +func (f *fp) BigInt() *big.Int { + buffer := f.Bytes() + return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:])) +} + +// Raw converts this element into the a [FieldLimbs]uint64 +func (f *fp) Raw() [Limbs]uint64 { + t := new(fp).fromMontgomery(f) + return *t +} + +// CMove performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f *fp) CMove(arg1, arg2 *fp, choice int) *fp { + mask := uint64(-choice) + f[0] = arg1[0] ^ ((arg1[0] ^ arg2[0]) & mask) + f[1] = arg1[1] ^ ((arg1[1] ^ arg2[1]) & mask) + f[2] = arg1[2] ^ ((arg1[2] ^ arg2[2]) & mask) + f[3] = arg1[3] ^ ((arg1[3] ^ arg2[3]) & mask) + f[4] = arg1[4] ^ ((arg1[4] ^ arg2[4]) & mask) + f[5] = arg1[5] ^ ((arg1[5] ^ arg2[5]) & mask) + return f +} + +// CNeg conditionally negates a if choice == 1 +func (f *fp) CNeg(a *fp, choice int) *fp { + var t fp + t.Neg(a) + return f.CMove(f, &t, choice) +} + +// Exp raises base^exp. +func (f *fp) Exp(base, exp *fp) *fp { + e := (&fp{}).fromMontgomery(exp) + return f.pow(base, e) +} + +func (f *fp) pow(base, e *fp) *fp { + var tmp, res fp + res.SetOne() + + for i := len(e) - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + res.Square(&res) + tmp.Mul(&res, base) + res.CMove(&res, &tmp, int(e[i]>>j)&1) + } + } + f[0] = res[0] + f[1] = res[1] + f[2] = res[2] + f[3] = res[3] + f[4] = res[4] + f[5] = res[5] + return f +} + +// montReduce performs the montgomery reduction +func (f *fp) montReduce(r *[2 * Limbs]uint64) *fp { + // Taken from Algorithm 14.32 in Handbook of Applied Cryptography + var r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, carry, k uint64 + var rr fp + + k = r[0] * inv + _, carry = mac(r[0], k, modulus[0], 0) + r1, carry = mac(r[1], k, modulus[1], carry) + r2, carry = mac(r[2], k, modulus[2], carry) + r3, carry = mac(r[3], k, modulus[3], carry) + r4, carry = mac(r[4], k, modulus[4], carry) + r5, carry = mac(r[5], k, modulus[5], carry) + r6, r7 = adc(r[6], 0, carry) + + k = r1 * inv + _, carry = mac(r1, k, modulus[0], 0) + r2, carry = mac(r2, k, modulus[1], carry) + r3, carry = mac(r3, k, modulus[2], carry) + r4, carry = mac(r4, k, modulus[3], carry) + r5, carry = mac(r5, k, modulus[4], carry) + r6, carry = mac(r6, k, modulus[5], carry) + r7, r8 = adc(r7, r[7], carry) + + k = r2 * inv + _, carry = mac(r2, k, modulus[0], 0) + r3, carry = mac(r3, k, modulus[1], carry) + r4, carry = mac(r4, k, modulus[2], carry) + r5, carry = mac(r5, k, modulus[3], carry) + r6, carry = mac(r6, k, modulus[4], carry) + r7, carry = mac(r7, k, modulus[5], carry) + r8, r9 = adc(r8, r[8], carry) + + k = r3 * inv + _, carry = mac(r3, k, modulus[0], 0) + r4, carry = mac(r4, k, modulus[1], carry) + r5, carry = mac(r5, k, modulus[2], carry) + r6, carry = mac(r6, k, modulus[3], carry) + r7, carry = mac(r7, k, modulus[4], carry) + r8, carry = mac(r8, k, modulus[5], carry) + r9, r10 = adc(r9, r[9], carry) + + k = r4 * inv + _, carry = mac(r4, k, modulus[0], 0) + r5, carry = mac(r5, k, modulus[1], carry) + r6, carry = mac(r6, k, modulus[2], carry) + r7, carry = mac(r7, k, modulus[3], carry) + r8, carry = mac(r8, k, modulus[4], carry) + r9, carry = mac(r9, k, modulus[5], carry) + r10, r11 = adc(r10, r[10], carry) + + k = r5 * inv + _, carry = mac(r5, k, modulus[0], 0) + rr[0], carry = mac(r6, k, modulus[1], carry) + rr[1], carry = mac(r7, k, modulus[2], carry) + rr[2], carry = mac(r8, k, modulus[3], carry) + rr[3], carry = mac(r9, k, modulus[4], carry) + rr[4], carry = mac(r10, k, modulus[5], carry) + rr[5], _ = adc(r11, r[11], carry) + + return f.Sub(&rr, &modulus) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp12.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp12.go new file mode 100644 index 0000000000..847930f2f8 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp12.go @@ -0,0 +1,231 @@ +package bls12381 + +import "io" + +// fp12 represents an element a + b w of fp^12 = fp^6 / w^2 - v. +type fp12 struct { + A, B fp6 +} + +// SetFp creates an element from a lower field +func (f *fp12) SetFp(a *fp) *fp12 { + f.A.SetFp(a) + f.B.SetZero() + return f +} + +// SetFp2 creates an element from a lower field +func (f *fp12) SetFp2(a *fp2) *fp12 { + f.A.SetFp2(a) + f.B.SetZero() + return f +} + +// SetFp6 creates an element from a lower field +func (f *fp12) SetFp6(a *fp6) *fp12 { + f.A.Set(a) + f.B.SetZero() + return f +} + +// Set copies the value `a` +func (f *fp12) Set(a *fp12) *fp12 { + f.A.Set(&a.A) + f.B.Set(&a.B) + return f +} + +// SetZero fp6 to zero +func (f *fp12) SetZero() *fp12 { + f.A.SetZero() + f.B.SetZero() + return f +} + +// SetOne fp6 to multiplicative identity element +func (f *fp12) SetOne() *fp12 { + f.A.SetOne() + f.B.SetZero() + return f +} + +// Random generates a random field element +func (f *fp12) Random(reader io.Reader) (*fp12, error) { + a, err := new(fp6).Random(reader) + if err != nil { + return nil, err + } + b, err := new(fp6).Random(reader) + if err != nil { + return nil, err + } + f.A.Set(a) + f.B.Set(b) + return f, nil +} + +// Square computes arg^2 +func (f *fp12) Square(arg *fp12) *fp12 { + var ab, apb, aTick, bTick, t fp6 + + ab.Mul(&arg.A, &arg.B) + apb.Add(&arg.A, &arg.B) + + aTick.MulByNonResidue(&arg.B) + aTick.Add(&aTick, &arg.A) + aTick.Mul(&aTick, &apb) + aTick.Sub(&aTick, &ab) + t.MulByNonResidue(&ab) + aTick.Sub(&aTick, &t) + + bTick.Double(&ab) + + f.A.Set(&aTick) + f.B.Set(&bTick) + return f +} + +// Invert computes this element's field inversion +func (f *fp12) Invert(arg *fp12) (*fp12, int) { + var a, b, t fp6 + a.Square(&arg.A) + b.Square(&arg.B) + b.MulByNonResidue(&b) + a.Sub(&a, &b) + _, wasInverted := t.Invert(&a) + + a.Mul(&arg.A, &t) + t.Neg(&t) + b.Mul(&arg.B, &t) + f.A.CMove(&f.A, &a, wasInverted) + f.B.CMove(&f.B, &b, wasInverted) + return f, wasInverted +} + +// Add computes arg1+arg2 +func (f *fp12) Add(arg1, arg2 *fp12) *fp12 { + f.A.Add(&arg1.A, &arg2.A) + f.B.Add(&arg1.B, &arg2.B) + return f +} + +// Sub computes arg1-arg2 +func (f *fp12) Sub(arg1, arg2 *fp12) *fp12 { + f.A.Sub(&arg1.A, &arg2.A) + f.B.Sub(&arg1.B, &arg2.B) + return f +} + +// Mul computes arg1*arg2 +func (f *fp12) Mul(arg1, arg2 *fp12) *fp12 { + var aa, bb, a2b2, a, b fp6 + + aa.Mul(&arg1.A, &arg2.A) + bb.Mul(&arg1.B, &arg2.B) + a2b2.Add(&arg2.A, &arg2.B) + b.Add(&arg1.A, &arg1.B) + b.Mul(&b, &a2b2) + b.Sub(&b, &aa) + b.Sub(&b, &bb) + a.MulByNonResidue(&bb) + a.Add(&a, &aa) + + f.A.Set(&a) + f.B.Set(&b) + return f +} + +// Neg computes the field negation +func (f *fp12) Neg(arg *fp12) *fp12 { + f.A.Neg(&arg.A) + f.B.Neg(&arg.B) + return f +} + +// MulByABD computes arg * a * b * c +func (f *fp12) MulByABD(arg *fp12, a, b, d *fp2) *fp12 { + var aa, bb, aTick, bTick fp6 + var bd fp2 + + aa.MulByAB(&arg.A, a, b) + bb.MulByB(&arg.B, d) + bd.Add(b, d) + + bTick.Add(&arg.A, &arg.B) + bTick.MulByAB(&bTick, a, &bd) + bTick.Sub(&bTick, &aa) + bTick.Sub(&bTick, &bb) + + aTick.MulByNonResidue(&bb) + aTick.Add(&aTick, &aa) + + f.A.Set(&aTick) + f.B.Set(&bTick) + + return f +} + +// Conjugate computes the field conjugation +func (f *fp12) Conjugate(arg *fp12) *fp12 { + f.A.Set(&arg.A) + f.B.Neg(&arg.B) + return f +} + +// FrobeniusMap raises this element to p. +func (f *fp12) FrobeniusMap(arg *fp12) *fp12 { + var a, b, up1epm1div6 fp6 + + // (u + 1)^((p - 1) / 6) + up1epm1div6.A = fp2{ + A: fp{ + 0x07089552b319d465, + 0xc6695f92b50a8313, + 0x97e83cccd117228f, + 0xa35baecab2dc29ee, + 0x1ce393ea5daace4d, + 0x08f2220fb0fb66eb, + }, + B: fp{ + 0xb2f66aad4ce5d646, + 0x5842a06bfc497cec, + 0xcf4895d42599d394, + 0xc11b9cba40a8e8d0, + 0x2e3813cbe5a0de89, + 0x110eefda88847faf, + }, + } + + a.FrobeniusMap(&arg.A) + b.FrobeniusMap(&arg.B) + + // b' = b' * (u + 1)^((p - 1) / 6) + b.Mul(&b, &up1epm1div6) + + f.A.Set(&a) + f.B.Set(&b) + return f +} + +// Equal returns 1 if fp12 == rhs, 0 otherwise +func (f *fp12) Equal(rhs *fp12) int { + return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B) +} + +// IsZero returns 1 if fp6 == 0, 0 otherwise +func (f *fp12) IsZero() int { + return f.A.IsZero() & f.B.IsZero() +} + +// IsOne returns 1 if fp12 == 1, 0 otherwise +func (f *fp12) IsOne() int { + return f.A.IsOne() & f.B.IsZero() +} + +// CMove performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f *fp12) CMove(arg1, arg2 *fp12, choice int) *fp12 { + f.A.CMove(&arg1.A, &arg2.A, choice) + f.B.CMove(&arg1.B, &arg2.B, choice) + return f +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp2.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp2.go new file mode 100644 index 0000000000..85cdd10b8c --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp2.go @@ -0,0 +1,344 @@ +package bls12381 + +import ( + "io" +) + +// fp2 is a point in p^2 +type fp2 struct { + A, B fp +} + +// Set copies a into fp2 +func (f *fp2) Set(a *fp2) *fp2 { + f.A.Set(&a.A) + f.B.Set(&a.B) + return f +} + +// SetZero fp2 = 0 +func (f *fp2) SetZero() *fp2 { + f.A.SetZero() + f.B.SetZero() + return f +} + +// SetOne fp2 to the multiplicative identity element +func (f *fp2) SetOne() *fp2 { + f.A.SetOne() + f.B.SetZero() + return f +} + +// SetFp creates an element from a lower field +func (f *fp2) SetFp(a *fp) *fp2 { + f.A.Set(a) + f.B.SetZero() + return f +} + +// Random generates a random field element +func (f *fp2) Random(reader io.Reader) (*fp2, error) { + a, err := new(fp).Random(reader) + if err != nil { + return nil, err + } + b, err := new(fp).Random(reader) + if err != nil { + return nil, err + } + f.A = *a + f.B = *b + return f, nil +} + +// IsZero returns 1 if fp2 == 0, 0 otherwise +func (f *fp2) IsZero() int { + return f.A.IsZero() & f.B.IsZero() +} + +// IsOne returns 1 if fp2 == 1, 0 otherwise +func (f *fp2) IsOne() int { + return f.A.IsOne() & f.B.IsZero() +} + +// Equal returns 1 if f == rhs, 0 otherwise +func (f *fp2) Equal(rhs *fp2) int { + return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B) +} + +// LexicographicallyLargest returns 1 if +// this element is strictly lexicographically larger than its negation +// 0 otherwise +func (f *fp2) LexicographicallyLargest() int { + // If this element's B coefficient is lexicographically largest + // then it is lexicographically largest. Otherwise, in the event + // the B coefficient is zero and the A coefficient is + // lexicographically largest, then this element is lexicographically + // largest. + + return f.B.LexicographicallyLargest() | + f.B.IsZero()&f.A.LexicographicallyLargest() +} + +// Sgn0 returns the lowest bit value +func (f *fp2) Sgn0() int { + // if A = 0 return B.Sgn0 else A.Sgn0 + a := f.A.IsZero() + t := f.B.Sgn0() & a + a = -a + 1 + t |= f.A.Sgn0() & a + return t +} + +// FrobeniusMap raises this element to p. +func (f *fp2) FrobeniusMap(a *fp2) *fp2 { + // This is always just a conjugation. If you're curious why, here's + // an article about it: https://alicebob.cryptoland.net/the-frobenius-endomorphism-with-finite-fields/ + return f.Conjugate(a) +} + +// Conjugate computes the conjugation of this element +func (f *fp2) Conjugate(a *fp2) *fp2 { + f.A.Set(&a.A) + f.B.Neg(&a.B) + return f +} + +// MulByNonResidue computes the following: +// multiply a + bu by u + 1, getting +// au + a + bu^2 + bu +// and because u^2 = -1, we get +// (a - b) + (a + b)u +func (f *fp2) MulByNonResidue(a *fp2) *fp2 { + var aa, bb fp + aa.Sub(&a.A, &a.B) + bb.Add(&a.A, &a.B) + f.A.Set(&aa) + f.B.Set(&bb) + return f +} + +// Square computes the square of this element +func (f *fp2) Square(arg *fp2) *fp2 { + var a, b, c fp + + // Complex squaring: + // + // v0 = a * b + // a' = (a + b) * (a + \beta*b) - v0 - \beta * v0 + // b' = 2 * v0 + // + // In BLS12-381's F_{p^2}, our \beta is -1, so we + // can modify this formula: + // + // a' = (a + b) * (a - b) + // b' = 2 * a * b + a.Add(&arg.A, &arg.B) + b.Sub(&arg.A, &arg.B) + c.Add(&arg.A, &arg.A) + + f.A.Mul(&a, &b) + f.B.Mul(&c, &arg.B) + return f +} + +// Add performs field addition +func (f *fp2) Add(arg1, arg2 *fp2) *fp2 { + f.A.Add(&arg1.A, &arg2.A) + f.B.Add(&arg1.B, &arg2.B) + return f +} + +// Double doubles specified element +func (f *fp2) Double(a *fp2) *fp2 { + f.A.Double(&a.A) + f.B.Double(&a.B) + return f +} + +// Sub performs field subtraction +func (f *fp2) Sub(arg1, arg2 *fp2) *fp2 { + f.A.Sub(&arg1.A, &arg2.A) + f.B.Sub(&arg1.B, &arg2.B) + return f +} + +// Mul computes Karatsuba multiplication +func (f *fp2) Mul(arg1, arg2 *fp2) *fp2 { + var v0, v1, t, a, b fp + + // Karatsuba multiplication: + // + // v0 = a0 * b0 + // v1 = a1 * b1 + // c0 = v0 + \beta * v1 + // c1 = (a0 + a1) * (b0 + b1) - v0 - v1 + // + // In BLS12-381's F_{p^2}, our \beta is -1, so we + // can modify this formula. (Also, since we always + // subtract v1, we can compute v1 = -a1 * b1.) + // + // v0 = a0 * a1 + // v1 = (-b0) * b1 + // a' = v0 + v1 + // b' = (a0 + b0) * (a1 + b1) - v0 + v1 + v0.Mul(&arg1.A, &arg2.A) + v1.Mul(new(fp).Neg(&arg1.B), &arg2.B) + + a.Add(&v0, &v1) + b.Add(&arg1.A, &arg1.B) + t.Add(&arg2.A, &arg2.B) + b.Mul(&b, &t) + b.Sub(&b, &v0) + b.Add(&b, &v1) + f.A.Set(&a) + f.B.Set(&b) + return f +} + +func (f *fp2) Mul0(arg1 *fp2, arg2 *fp) *fp2 { + f.A.Mul(&arg1.A, arg2) + f.B.Mul(&arg1.B, arg2) + return f +} + +// MulBy3b returns arg * 12 or 3 * b +func (f *fp2) MulBy3b(arg *fp2) *fp2 { + return f.Mul(arg, &curveG23B) +} + +// Neg performs field negation +func (f *fp2) Neg(a *fp2) *fp2 { + f.A.Neg(&a.A) + f.B.Neg(&a.B) + return f +} + +// Sqrt performs field square root +func (f *fp2) Sqrt(a *fp2) (*fp2, int) { + // Algorithm 9, https://eprint.iacr.org/2012/685.pdf + // with constant time modifications. + var a1, alpha, x0, t, res, res2 fp2 + e1 := a.IsZero() + // a1 = self^((p - 3) / 4) + a1.pow(a, &[Limbs]uint64{ + 0xee7fbfffffffeaaa, + 0x07aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x0680447a8e5ff9a6, + }) + + // alpha = a1^2 * a = a^((p - 3) / 2 + 1) = a^((p - 1) / 2) + alpha.Square(&a1) + alpha.Mul(&alpha, a) + + // x0 = self^((p + 1) / 4) + x0.Mul(&a1, a) + + // In the event that alpha = -1, the element is order p - 1. So + // we're just trying to get the square of an element of the subfield + // fp. This is given by x0 * u, since u = sqrt(-1). Since the element + // x0 = a + bu has b = 0, the solution is therefore au. + res2.A.Neg(&x0.B) + res2.B.Set(&x0.A) + // alpha == -1 + e2 := alpha.Equal(&fp2{ + A: fp{ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x07e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x040ab3263eff0206, + }, + B: fp{}, + }) + + // Otherwise, the correct solution is (1 + alpha)^((p - 1) // 2) * x0 + t.SetOne() + t.Add(&t, &alpha) + t.pow(&t, &[Limbs]uint64{ + 0xdcff7fffffffd555, + 0x0f55ffff58a9ffff, + 0xb39869507b587b12, + 0xb23ba5c279c2895f, + 0x258dd3db21a5d66b, + 0x0d0088f51cbff34d, + }) + t.Mul(&t, &x0) + // if a = 0, then its zero + res.CMove(&res2, &res, e1) + // if alpha = -1, its not (1 + alpha)^((p - 1) // 2) * x0 + // but au + res.CMove(&t, &res, e2) + + // is the result^2 = a + t.Square(&res) + e3 := t.Equal(a) + f.CMove(f, &res, e3) + return f, e3 +} + +// Invert computes the multiplicative inverse of this field +// element, returning the original value of fp2 +// in the case that this element is zero. +func (f *fp2) Invert(arg *fp2) (*fp2, int) { + // We wish to find the multiplicative inverse of a nonzero + // element a + bu in fp2. We leverage an identity + // + // (a + bu)(a - bu) = a^2 + b^2 + // + // which holds because u^2 = -1. This can be rewritten as + // + // (a + bu)(a - bu)/(a^2 + b^2) = 1 + // + // because a^2 + b^2 = 0 has no nonzero solutions for (a, b). + // This gives that (a - bu)/(a^2 + b^2) is the inverse + // of (a + bu). Importantly, this can be computing using + // only a single inversion in fp. + var a, b, t fp + a.Square(&arg.A) + b.Square(&arg.B) + a.Add(&a, &b) + _, wasInverted := t.Invert(&a) + // a * t + a.Mul(&arg.A, &t) + // b * -t + b.Neg(&t) + b.Mul(&b, &arg.B) + f.A.CMove(&f.A, &a, wasInverted) + f.B.CMove(&f.B, &b, wasInverted) + return f, wasInverted +} + +// CMove performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f *fp2) CMove(arg1, arg2 *fp2, choice int) *fp2 { + f.A.CMove(&arg1.A, &arg2.A, choice) + f.B.CMove(&arg1.B, &arg2.B, choice) + return f +} + +// CNeg conditionally negates a if choice == 1 +func (f *fp2) CNeg(a *fp2, choice int) *fp2 { + var t fp2 + t.Neg(a) + return f.CMove(f, &t, choice) +} + +func (f *fp2) pow(base *fp2, exp *[Limbs]uint64) *fp2 { + res := (&fp2{}).SetOne() + tmp := (&fp2{}).SetZero() + + for i := len(exp) - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + res.Square(res) + tmp.Mul(res, base) + res.CMove(res, tmp, int(exp[i]>>j)&1) + } + } + return f.Set(res) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp6.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp6.go new file mode 100644 index 0000000000..0863fd152e --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fp6.go @@ -0,0 +1,340 @@ +package bls12381 + +import "io" + +// fp6 represents an element +// a + b v + c v^2 of fp^6 = fp^2 / v^3 - u - 1. +type fp6 struct { + A, B, C fp2 +} + +// Set fp6 = a +func (f *fp6) Set(a *fp6) *fp6 { + f.A.Set(&a.A) + f.B.Set(&a.B) + f.C.Set(&a.C) + return f +} + +// SetFp creates an element from a lower field +func (f *fp6) SetFp(a *fp) *fp6 { + f.A.SetFp(a) + f.B.SetZero() + f.C.SetZero() + return f +} + +// SetFp2 creates an element from a lower field +func (f *fp6) SetFp2(a *fp2) *fp6 { + f.A.Set(a) + f.B.SetZero() + f.C.SetZero() + return f +} + +// SetZero fp6 to zero +func (f *fp6) SetZero() *fp6 { + f.A.SetZero() + f.B.SetZero() + f.C.SetZero() + return f +} + +// SetOne fp6 to multiplicative identity element +func (f *fp6) SetOne() *fp6 { + f.A.SetOne() + f.B.SetZero() + f.C.SetZero() + return f +} + +// Random generates a random field element +func (f *fp6) Random(reader io.Reader) (*fp6, error) { + a, err := new(fp2).Random(reader) + if err != nil { + return nil, err + } + b, err := new(fp2).Random(reader) + if err != nil { + return nil, err + } + c, err := new(fp2).Random(reader) + if err != nil { + return nil, err + } + f.A.Set(a) + f.B.Set(b) + f.C.Set(c) + return f, nil +} + +// Add computes arg1+arg2 +func (f *fp6) Add(arg1, arg2 *fp6) *fp6 { + f.A.Add(&arg1.A, &arg2.A) + f.B.Add(&arg1.B, &arg2.B) + f.C.Add(&arg1.C, &arg2.C) + return f +} + +// Double computes arg1+arg1 +func (f *fp6) Double(arg *fp6) *fp6 { + return f.Add(arg, arg) +} + +// Sub computes arg1-arg2 +func (f *fp6) Sub(arg1, arg2 *fp6) *fp6 { + f.A.Sub(&arg1.A, &arg2.A) + f.B.Sub(&arg1.B, &arg2.B) + f.C.Sub(&arg1.C, &arg2.C) + return f +} + +// Mul computes arg1*arg2 +func (f *fp6) Mul(arg1, arg2 *fp6) *fp6 { + var aa, bb, cc, s, t1, t2, t3 fp2 + + aa.Mul(&arg1.A, &arg2.A) + bb.Mul(&arg1.B, &arg2.B) + cc.Mul(&arg1.C, &arg2.C) + + t1.Add(&arg2.B, &arg2.C) + s.Add(&arg1.B, &arg1.C) + t1.Mul(&t1, &s) + t1.Sub(&t1, &bb) + t1.Sub(&t1, &cc) + t1.MulByNonResidue(&t1) + t1.Add(&t1, &aa) + + t3.Add(&arg2.A, &arg2.C) + s.Add(&arg1.A, &arg1.C) + t3.Mul(&t3, &s) + t3.Sub(&t3, &aa) + t3.Add(&t3, &bb) + t3.Sub(&t3, &cc) + + t2.Add(&arg2.A, &arg2.B) + s.Add(&arg1.A, &arg1.B) + t2.Mul(&t2, &s) + t2.Sub(&t2, &aa) + t2.Sub(&t2, &bb) + cc.MulByNonResidue(&cc) + t2.Add(&t2, &cc) + + f.A.Set(&t1) + f.B.Set(&t2) + f.C.Set(&t3) + return f +} + +// MulByB scales this field by a scalar in the B coefficient +func (f *fp6) MulByB(arg *fp6, b *fp2) *fp6 { + var bB, t1, t2 fp2 + bB.Mul(&arg.B, b) + // (b + c) * arg2 - bB + t1.Add(&arg.B, &arg.C) + t1.Mul(&t1, b) + t1.Sub(&t1, &bB) + t1.MulByNonResidue(&t1) + + t2.Add(&arg.A, &arg.B) + t2.Mul(&t2, b) + t2.Sub(&t2, &bB) + + f.A.Set(&t1) + f.B.Set(&t2) + f.C.Set(&bB) + return f +} + +// MulByAB scales this field by scalars in the A and B coefficients +func (f *fp6) MulByAB(arg *fp6, a, b *fp2) *fp6 { + var aA, bB, t1, t2, t3 fp2 + + aA.Mul(&arg.A, a) + bB.Mul(&arg.B, b) + + t1.Add(&arg.B, &arg.C) + t1.Mul(&t1, b) + t1.Sub(&t1, &bB) + t1.MulByNonResidue(&t1) + t1.Add(&t1, &aA) + + t2.Add(a, b) + t3.Add(&arg.A, &arg.B) + t2.Mul(&t2, &t3) + t2.Sub(&t2, &aA) + t2.Sub(&t2, &bB) + + t3.Add(&arg.A, &arg.C) + t3.Mul(&t3, a) + t3.Sub(&t3, &aA) + t3.Add(&t3, &bB) + + f.A.Set(&t1) + f.B.Set(&t2) + f.C.Set(&t3) + + return f +} + +// MulByNonResidue multiplies by quadratic nonresidue v. +func (f *fp6) MulByNonResidue(arg *fp6) *fp6 { + // Given a + bv + cv^2, this produces + // av + bv^2 + cv^3 + // but because v^3 = u + 1, we have + // c(u + 1) + av + bv^2 + var a, b, c fp2 + a.MulByNonResidue(&arg.C) + b.Set(&arg.A) + c.Set(&arg.B) + f.A.Set(&a) + f.B.Set(&b) + f.C.Set(&c) + return f +} + +// FrobeniusMap raises this element to p. +func (f *fp6) FrobeniusMap(arg *fp6) *fp6 { + var a, b, c fp2 + pm1Div3 := fp2{ + A: fp{}, + B: fp{ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x03f97d6e83d050d2, + 0x18f0206554638741, + }, + } + p2m2Div3 := fp2{ + A: fp{ + 0x890dc9e4867545c3, + 0x2af322533285a5d5, + 0x50880866309b7e2c, + 0xa20d1b8c7e881024, + 0x14e4f04fe2db9068, + 0x14e56d3f1564853a, + }, + B: fp{}, + } + a.FrobeniusMap(&arg.A) + b.FrobeniusMap(&arg.B) + c.FrobeniusMap(&arg.C) + + // b = b * (u + 1)^((p - 1) / 3) + b.Mul(&b, &pm1Div3) + + // c = c * (u + 1)^((2p - 2) / 3) + c.Mul(&c, &p2m2Div3) + + f.A.Set(&a) + f.B.Set(&b) + f.C.Set(&c) + return f +} + +// Square computes fp6^2 +func (f *fp6) Square(arg *fp6) *fp6 { + var s0, s1, s2, s3, s4, ab, bc fp2 + + s0.Square(&arg.A) + ab.Mul(&arg.A, &arg.B) + s1.Double(&ab) + s2.Sub(&arg.A, &arg.B) + s2.Add(&s2, &arg.C) + s2.Square(&s2) + bc.Mul(&arg.B, &arg.C) + s3.Double(&bc) + s4.Square(&arg.C) + + f.A.MulByNonResidue(&s3) + f.A.Add(&f.A, &s0) + + f.B.MulByNonResidue(&s4) + f.B.Add(&f.B, &s1) + + // s1 + s2 + s3 - s0 - s4 + f.C.Add(&s1, &s2) + f.C.Add(&f.C, &s3) + f.C.Sub(&f.C, &s0) + f.C.Sub(&f.C, &s4) + + return f +} + +// Invert computes this element's field inversion +func (f *fp6) Invert(arg *fp6) (*fp6, int) { + var a, b, c, s, t fp2 + + // a' = a^2 - (b * c).mul_by_nonresidue() + a.Mul(&arg.B, &arg.C) + a.MulByNonResidue(&a) + t.Square(&arg.A) + a.Sub(&t, &a) + + // b' = (c^2).mul_by_nonresidue() - (a * b) + b.Square(&arg.C) + b.MulByNonResidue(&b) + t.Mul(&arg.A, &arg.B) + b.Sub(&b, &t) + + // c' = b^2 - (a * c) + c.Square(&arg.B) + t.Mul(&arg.A, &arg.C) + c.Sub(&c, &t) + + // t = ((b * c') + (c * b')).mul_by_nonresidue() + (a * a') + s.Mul(&arg.B, &c) + t.Mul(&arg.C, &b) + s.Add(&s, &t) + s.MulByNonResidue(&s) + + t.Mul(&arg.A, &a) + s.Add(&s, &t) + + _, wasInverted := t.Invert(&s) + + // newA = a' * t^-1 + s.Mul(&a, &t) + f.A.CMove(&f.A, &s, wasInverted) + // newB = b' * t^-1 + s.Mul(&b, &t) + f.B.CMove(&f.B, &s, wasInverted) + // newC = c' * t^-1 + s.Mul(&c, &t) + f.C.CMove(&f.C, &s, wasInverted) + return f, wasInverted +} + +// Neg computes the field negation +func (f *fp6) Neg(arg *fp6) *fp6 { + f.A.Neg(&arg.A) + f.B.Neg(&arg.B) + f.C.Neg(&arg.C) + return f +} + +// IsZero returns 1 if fp6 == 0, 0 otherwise +func (f *fp6) IsZero() int { + return f.A.IsZero() & f.B.IsZero() & f.C.IsZero() +} + +// IsOne returns 1 if fp6 == 1, 0 otherwise +func (f *fp6) IsOne() int { + return f.A.IsOne() & f.B.IsZero() & f.B.IsZero() +} + +// Equal returns 1 if fp6 == rhs, 0 otherwise +func (f *fp6) Equal(rhs *fp6) int { + return f.A.Equal(&rhs.A) & f.B.Equal(&rhs.B) & f.C.Equal(&rhs.C) +} + +// CMove performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f *fp6) CMove(arg1, arg2 *fp6, choice int) *fp6 { + f.A.CMove(&arg1.A, &arg2.A, choice) + f.B.CMove(&arg1.B, &arg2.B, choice) + f.C.CMove(&arg1.C, &arg2.C, choice) + return f +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fq.go new file mode 100644 index 0000000000..ee4eb39d88 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/fq.go @@ -0,0 +1,413 @@ +package bls12381 + +import ( + "encoding/binary" + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +type Fq [native.FieldLimbs]uint64 + +var bls12381FqInitonce sync.Once +var bls12381FqParams native.FieldParams + +// 2^S * t = MODULUS - 1 with t odd +const fqS = 32 + +// qInv = -(q^{-1} mod 2^64) mod 2^64 +const qInv = 0xfffffffeffffffff + +// fqGenerator = 7 (multiplicative fqGenerator of r-1 order, that is also quadratic nonresidue) +var fqGenerator = [native.FieldLimbs]uint64{0x0000000efffffff1, 0x17e363d300189c0f, 0xff9c57876f8457b0, 0x351332208fc5a8c4} + +// fqModulus +var fqModulus = [native.FieldLimbs]uint64{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48} + +func Bls12381FqNew() *native.Field { + return &native.Field{ + Value: [native.FieldLimbs]uint64{}, + Params: getBls12381FqParams(), + Arithmetic: bls12381FqArithmetic{}, + } +} + +func bls12381FqParamsInit() { + bls12381FqParams = native.FieldParams{ + R: [native.FieldLimbs]uint64{0x00000001fffffffe, 0x5884b7fa00034802, 0x998c4fefecbc4ff5, 0x1824b159acc5056f}, + R2: [native.FieldLimbs]uint64{0xc999e990f3f29c6d, 0x2b6cedcb87925c23, 0x05d314967254398f, 0x0748d9d99f59ff11}, + R3: [native.FieldLimbs]uint64{0xc62c1807439b73af, 0x1b3e0d188cf06990, 0x73d13c71c7b5f418, 0x6e2a5bb9c8db33e9}, + Modulus: [native.FieldLimbs]uint64{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48}, + BiModulus: new(big.Int).SetBytes([]byte{ + 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05, 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01}), + } +} + +func getBls12381FqParams() *native.FieldParams { + bls12381FqInitonce.Do(bls12381FqParamsInit) + return &bls12381FqParams +} + +// bls12381FqArithmetic is a struct with all the methods needed for working +// in mod q +type bls12381FqArithmetic struct{} + +// ToMontgomery converts this field to montgomery form +func (f bls12381FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) { + // arg.R^0 * R^2 / R = arg.R + f.Mul(out, arg, &getBls12381FqParams().R2) +} + +// FromMontgomery converts this field from montgomery form +func (f bls12381FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) { + // Mul by 1 is division by 2^256 mod q + //f.Mul(out, arg, &[native.FieldLimbs]uint64{1, 0, 0, 0}) + f.montReduce(out, &[native.FieldLimbs * 2]uint64{arg[0], arg[1], arg[2], arg[3], 0, 0, 0, 0}) +} + +// Neg performs modular negation +func (f bls12381FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) { + // Subtract `arg` from `fqModulus`. Ignore final borrow + // since it can't underflow. + var t [native.FieldLimbs]uint64 + var borrow uint64 + t[0], borrow = sbb(fqModulus[0], arg[0], 0) + t[1], borrow = sbb(fqModulus[1], arg[1], borrow) + t[2], borrow = sbb(fqModulus[2], arg[2], borrow) + t[3], _ = sbb(fqModulus[3], arg[3], borrow) + + // t could be `fqModulus` if `arg`=0. Set mask=0 if self=0 + // and 0xff..ff if `arg`!=0 + mask := t[0] | t[1] | t[2] | t[3] + mask = -((mask | -mask) >> 63) + out[0] = t[0] & mask + out[1] = t[1] & mask + out[2] = t[2] & mask + out[3] = t[3] & mask +} + +// Square performs modular square +func (f bls12381FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) { + var r [2 * native.FieldLimbs]uint64 + var carry uint64 + + r[1], carry = mac(0, arg[0], arg[1], 0) + r[2], carry = mac(0, arg[0], arg[2], carry) + r[3], r[4] = mac(0, arg[0], arg[3], carry) + + r[3], carry = mac(r[3], arg[1], arg[2], 0) + r[4], r[5] = mac(r[4], arg[1], arg[3], carry) + + r[5], r[6] = mac(r[5], arg[2], arg[3], 0) + + r[7] = r[6] >> 63 + r[6] = (r[6] << 1) | r[5]>>63 + r[5] = (r[5] << 1) | r[4]>>63 + r[4] = (r[4] << 1) | r[3]>>63 + r[3] = (r[3] << 1) | r[2]>>63 + r[2] = (r[2] << 1) | r[1]>>63 + r[1] = r[1] << 1 + + r[0], carry = mac(0, arg[0], arg[0], 0) + r[1], carry = adc(0, r[1], carry) + r[2], carry = mac(r[2], arg[1], arg[1], carry) + r[3], carry = adc(0, r[3], carry) + r[4], carry = mac(r[4], arg[2], arg[2], carry) + r[5], carry = adc(0, r[5], carry) + r[6], carry = mac(r[6], arg[3], arg[3], carry) + r[7], _ = adc(0, r[7], carry) + + f.montReduce(out, &r) +} + +// Mul performs modular multiplication +func (f bls12381FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) { + // Schoolbook multiplication + var r [2 * native.FieldLimbs]uint64 + var carry uint64 + + r[0], carry = mac(0, arg1[0], arg2[0], 0) + r[1], carry = mac(0, arg1[0], arg2[1], carry) + r[2], carry = mac(0, arg1[0], arg2[2], carry) + r[3], r[4] = mac(0, arg1[0], arg2[3], carry) + + r[1], carry = mac(r[1], arg1[1], arg2[0], 0) + r[2], carry = mac(r[2], arg1[1], arg2[1], carry) + r[3], carry = mac(r[3], arg1[1], arg2[2], carry) + r[4], r[5] = mac(r[4], arg1[1], arg2[3], carry) + + r[2], carry = mac(r[2], arg1[2], arg2[0], 0) + r[3], carry = mac(r[3], arg1[2], arg2[1], carry) + r[4], carry = mac(r[4], arg1[2], arg2[2], carry) + r[5], r[6] = mac(r[5], arg1[2], arg2[3], carry) + + r[3], carry = mac(r[3], arg1[3], arg2[0], 0) + r[4], carry = mac(r[4], arg1[3], arg2[1], carry) + r[5], carry = mac(r[5], arg1[3], arg2[2], carry) + r[6], r[7] = mac(r[6], arg1[3], arg2[3], carry) + + f.montReduce(out, &r) +} + +// Add performs modular addition +func (f bls12381FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) { + var t [native.FieldLimbs]uint64 + var carry uint64 + + t[0], carry = adc(arg1[0], arg2[0], 0) + t[1], carry = adc(arg1[1], arg2[1], carry) + t[2], carry = adc(arg1[2], arg2[2], carry) + t[3], _ = adc(arg1[3], arg2[3], carry) + + // Subtract the fqModulus to ensure the value + // is smaller. + f.Sub(out, &t, &fqModulus) +} + +// Sub performs modular subtraction +func (f bls12381FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) { + d0, borrow := sbb(arg1[0], arg2[0], 0) + d1, borrow := sbb(arg1[1], arg2[1], borrow) + d2, borrow := sbb(arg1[2], arg2[2], borrow) + d3, borrow := sbb(arg1[3], arg2[3], borrow) + + // If underflow occurred on the final limb, borrow 0xff...ff, otherwise + // borrow = 0x00...00. Conditionally mask to add the fqModulus + borrow = -borrow + d0, carry := adc(d0, fqModulus[0]&borrow, 0) + d1, carry = adc(d1, fqModulus[1]&borrow, carry) + d2, carry = adc(d2, fqModulus[2]&borrow, carry) + d3, _ = adc(d3, fqModulus[3]&borrow, carry) + + out[0] = d0 + out[1] = d1 + out[2] = d2 + out[3] = d3 +} + +// Sqrt performs modular square root +func (f bls12381FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) { + // See sqrt_ts_ct at + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4 + // c1 := fqS + // c2 := (q - 1) / (2^c1) + c2 := [4]uint64{ + 0xfffe5bfeffffffff, + 0x09a1d80553bda402, + 0x299d7d483339d808, + 0x0000000073eda753, + } + // c3 := (c2 - 1) / 2 + c3 := [native.FieldLimbs]uint64{ + 0x7fff2dff7fffffff, + 0x04d0ec02a9ded201, + 0x94cebea4199cec04, + 0x0000000039f6d3a9, + } + //c4 := fqGenerator + var c5 [native.FieldLimbs]uint64 + native.Pow(&c5, &fqGenerator, &c2, getBls12381FqParams(), f) + //c5 := [native.FieldLimbs]uint64{0x1015708f7e368fe1, 0x31c6c5456ecc4511, 0x5281fe8998a19ea1, 0x0279089e10c63fe8} + var z, t, b, c, tv [native.FieldLimbs]uint64 + + native.Pow(&z, arg, &c3, getBls12381FqParams(), f) + f.Square(&t, &z) + f.Mul(&t, &t, arg) + f.Mul(&z, &z, arg) + + copy(b[:], t[:]) + copy(c[:], c5[:]) + + for i := fqS; i >= 2; i-- { + for j := 1; j <= i-2; j++ { + f.Square(&b, &b) + } + // if b == 1 flag = 0 else flag = 1 + flag := -(&native.Field{ + Value: b, + Params: getBls12381FqParams(), + Arithmetic: f, + }).IsOne() + 1 + f.Mul(&tv, &z, &c) + f.Selectznz(&z, &z, &tv, flag) + f.Square(&c, &c) + f.Mul(&tv, &t, &c) + f.Selectznz(&t, &t, &tv, flag) + copy(b[:], t[:]) + } + f.Square(&c, &z) + *wasSquare = (&native.Field{ + Value: c, + Params: getBls12381FqParams(), + Arithmetic: f, + }).Equal(&native.Field{ + Value: *arg, + Params: getBls12381FqParams(), + Arithmetic: f, + }) + f.Selectznz(out, out, &z, *wasSquare) +} + +// Invert performs modular inverse +func (f bls12381FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) { + // Using an addition chain from + // https://github.com/kwantam/addchain + var t0, t1, t2, t3, t4, t5, t6, t7, t8 [native.FieldLimbs]uint64 + var t9, t11, t12, t13, t14, t15, t16, t17 [native.FieldLimbs]uint64 + + f.Square(&t0, arg) + f.Mul(&t1, &t0, arg) + f.Square(&t16, &t0) + f.Square(&t6, &t16) + f.Mul(&t5, &t6, &t0) + f.Mul(&t0, &t6, &t16) + f.Mul(&t12, &t5, &t16) + f.Square(&t2, &t6) + f.Mul(&t7, &t5, &t6) + f.Mul(&t15, &t0, &t5) + f.Square(&t17, &t12) + f.Mul(&t1, &t1, &t17) + f.Mul(&t3, &t7, &t2) + f.Mul(&t8, &t1, &t17) + f.Mul(&t4, &t8, &t2) + f.Mul(&t9, &t8, &t7) + f.Mul(&t7, &t4, &t5) + f.Mul(&t11, &t4, &t17) + f.Mul(&t5, &t9, &t17) + f.Mul(&t14, &t7, &t15) + f.Mul(&t13, &t11, &t12) + f.Mul(&t12, &t11, &t17) + f.Mul(&t15, &t15, &t12) + f.Mul(&t16, &t16, &t15) + f.Mul(&t3, &t3, &t16) + f.Mul(&t17, &t17, &t3) + f.Mul(&t0, &t0, &t17) + f.Mul(&t6, &t6, &t0) + f.Mul(&t2, &t2, &t6) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t17) + native.Pow2k(&t0, &t0, 9, f) + f.Mul(&t0, &t0, &t16) + native.Pow2k(&t0, &t0, 9, f) + f.Mul(&t0, &t0, &t15) + native.Pow2k(&t0, &t0, 9, f) + f.Mul(&t0, &t0, &t15) + native.Pow2k(&t0, &t0, 7, f) + f.Mul(&t0, &t0, &t14) + native.Pow2k(&t0, &t0, 7, f) + f.Mul(&t0, &t0, &t13) + native.Pow2k(&t0, &t0, 10, f) + f.Mul(&t0, &t0, &t12) + native.Pow2k(&t0, &t0, 9, f) + f.Mul(&t0, &t0, &t11) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t8) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, arg) + native.Pow2k(&t0, &t0, 14, f) + f.Mul(&t0, &t0, &t9) + native.Pow2k(&t0, &t0, 10, f) + f.Mul(&t0, &t0, &t8) + native.Pow2k(&t0, &t0, 15, f) + f.Mul(&t0, &t0, &t7) + native.Pow2k(&t0, &t0, 10, f) + f.Mul(&t0, &t0, &t6) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t5) + native.Pow2k(&t0, &t0, 16, f) + f.Mul(&t0, &t0, &t3) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 7, f) + f.Mul(&t0, &t0, &t4) + native.Pow2k(&t0, &t0, 9, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t3) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t3) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 8, f) + f.Mul(&t0, &t0, &t2) + native.Pow2k(&t0, &t0, 5, f) + f.Mul(&t0, &t0, &t1) + native.Pow2k(&t0, &t0, 5, f) + f.Mul(&t0, &t0, &t1) + + *wasInverted = (&native.Field{ + Value: *arg, + Params: getBls12381FqParams(), + Arithmetic: f, + }).IsNonZero() + f.Selectznz(out, out, &t0, *wasInverted) +} + +// FromBytes converts a little endian byte array into a field element +func (f bls12381FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) { + out[0] = binary.LittleEndian.Uint64(arg[:8]) + out[1] = binary.LittleEndian.Uint64(arg[8:16]) + out[2] = binary.LittleEndian.Uint64(arg[16:24]) + out[3] = binary.LittleEndian.Uint64(arg[24:]) +} + +// ToBytes converts a field element to a little endian byte array +func (f bls12381FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) { + binary.LittleEndian.PutUint64(out[:8], arg[0]) + binary.LittleEndian.PutUint64(out[8:16], arg[1]) + binary.LittleEndian.PutUint64(out[16:24], arg[2]) + binary.LittleEndian.PutUint64(out[24:], arg[3]) +} + +// Selectznz performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f bls12381FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) { + b := uint64(-choice) + out[0] = arg1[0] ^ ((arg1[0] ^ arg2[0]) & b) + out[1] = arg1[1] ^ ((arg1[1] ^ arg2[1]) & b) + out[2] = arg1[2] ^ ((arg1[2] ^ arg2[2]) & b) + out[3] = arg1[3] ^ ((arg1[3] ^ arg2[3]) & b) +} + +func (f bls12381FqArithmetic) montReduce(out *[native.FieldLimbs]uint64, r *[2 * native.FieldLimbs]uint64) { + // Taken from Algorithm 14.32 in Handbook of Applied Cryptography + var r1, r2, r3, r4, r5, r6, carry, carry2, k uint64 + var rr [native.FieldLimbs]uint64 + + k = r[0] * qInv + _, carry = mac(r[0], k, fqModulus[0], 0) + r1, carry = mac(r[1], k, fqModulus[1], carry) + r2, carry = mac(r[2], k, fqModulus[2], carry) + r3, carry = mac(r[3], k, fqModulus[3], carry) + r4, carry2 = adc(r[4], 0, carry) + + k = r1 * qInv + _, carry = mac(r1, k, fqModulus[0], 0) + r2, carry = mac(r2, k, fqModulus[1], carry) + r3, carry = mac(r3, k, fqModulus[2], carry) + r4, carry = mac(r4, k, fqModulus[3], carry) + r5, carry2 = adc(r[5], carry2, carry) + + k = r2 * qInv + _, carry = mac(r2, k, fqModulus[0], 0) + r3, carry = mac(r3, k, fqModulus[1], carry) + r4, carry = mac(r4, k, fqModulus[2], carry) + r5, carry = mac(r5, k, fqModulus[3], carry) + r6, carry2 = adc(r[6], carry2, carry) + + k = r3 * qInv + _, carry = mac(r3, k, fqModulus[0], 0) + rr[0], carry = mac(r4, k, fqModulus[1], carry) + rr[1], carry = mac(r5, k, fqModulus[2], carry) + rr[2], carry = mac(r6, k, fqModulus[3], carry) + rr[3], _ = adc(r[7], carry2, carry) + + f.Sub(out, &rr, &fqModulus) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g1.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g1.go new file mode 100644 index 0000000000..a35d4adfae --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g1.go @@ -0,0 +1,1124 @@ +package bls12381 + +import ( + "fmt" + "io" + "math/big" + + "github.com/pkg/errors" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var ( + g1x = fp{ + 0x5cb38790fd530c16, + 0x7817fc679976fff5, + 0x154f95c7143ba1c1, + 0xf0ae6acdf3d0e747, + 0xedce6ecc21dbf440, + 0x120177419e0bfb75, + } + g1y = fp{ + 0xbaac93d50ce72271, + 0x8c22631a7918fd8e, + 0xdd595f13570725ce, + 0x51ac582950405194, + 0x0e1c8c3fad0059c0, + 0x0bbc3efc5008a26a, + } + curveG1B = fp{ + 0xaa270000000cfff3, + 0x53cc0032fc34000a, + 0x478fe97a6b0a807f, + 0xb1d37ebee6ba24d7, + 0x8ec9733bbf78ab2f, + 0x09d645513d83de7e, + } + osswuMapA = fp{ + 0x2f65aa0e9af5aa51, + 0x86464c2d1e8416c3, + 0xb85ce591b7bd31e2, + 0x27e11c91b5f24e7c, + 0x28376eda6bfc1835, + 0x155455c3e5071d85, + } + osswuMapB = fp{ + 0xfb996971fe22a1e0, + 0x9aa93eb35b742d6f, + 0x8c476013de99c5c4, + 0x873e27c3a221e571, + 0xca72b5e45a52d888, + 0x06824061418a386b, + } + osswuMapC1 = fp{ + 0xee7fbfffffffeaaa, + 0x07aaffffac54ffff, + 0xd9cc34a83dac3d89, + 0xd91dd2e13ce144af, + 0x92c6e9ed90d2eb35, + 0x0680447a8e5ff9a6, + } + osswuMapC2 = fp{ + 0x43b571cad3215f1f, + 0xccb460ef1c702dc2, + 0x742d884f4f97100b, + 0xdb2c3e3238a3382b, + 0xe40f3fa13fce8f88, + 0x0073a2af9892a2ff, + } + oswwuMapZ = fp{ + 0x886c00000023ffdc, + 0x0f70008d3090001d, + 0x77672417ed5828c3, + 0x9dac23e943dc1740, + 0x50553f1b9c131521, + 0x078c712fbe0ab6e8, + } + oswwuMapXd1 = *((&fp{}).Mul(&oswwuMapZ, &osswuMapA)) + negOsswuMapA = *(&fp{}).Neg(&osswuMapA) + + g1IsoXNum = []fp{ + { + 0x4d18b6f3af00131c, + 0x19fa219793fee28c, + 0x3f2885f1467f19ae, + 0x23dcea34f2ffb304, + 0xd15b58d2ffc00054, + 0x0913be200a20bef4, + }, + { + 0x898985385cdbbd8b, + 0x3c79e43cc7d966aa, + 0x1597e193f4cd233a, + 0x8637ef1e4d6623ad, + 0x11b22deed20d827b, + 0x07097bc5998784ad, + }, + { + 0xa542583a480b664b, + 0xfc7169c026e568c6, + 0x5ba2ef314ed8b5a6, + 0x5b5491c05102f0e7, + 0xdf6e99707d2a0079, + 0x0784151ed7605524, + }, + { + 0x494e212870f72741, + 0xab9be52fbda43021, + 0x26f5577994e34c3d, + 0x049dfee82aefbd60, + 0x65dadd7828505289, + 0x0e93d431ea011aeb, + }, + { + 0x90ee774bd6a74d45, + 0x7ada1c8a41bfb185, + 0x0f1a8953b325f464, + 0x104c24211be4805c, + 0x169139d319ea7a8f, + 0x09f20ead8e532bf6, + }, + { + 0x6ddd93e2f43626b7, + 0xa5482c9aa1ccd7bd, + 0x143245631883f4bd, + 0x2e0a94ccf77ec0db, + 0xb0282d480e56489f, + 0x18f4bfcbb4368929, + }, + { + 0x23c5f0c953402dfd, + 0x7a43ff6958ce4fe9, + 0x2c390d3d2da5df63, + 0xd0df5c98e1f9d70f, + 0xffd89869a572b297, + 0x1277ffc72f25e8fe, + }, + { + 0x79f4f0490f06a8a6, + 0x85f894a88030fd81, + 0x12da3054b18b6410, + 0xe2a57f6505880d65, + 0xbba074f260e400f1, + 0x08b76279f621d028, + }, + { + 0xe67245ba78d5b00b, + 0x8456ba9a1f186475, + 0x7888bff6e6b33bb4, + 0xe21585b9a30f86cb, + 0x05a69cdcef55feee, + 0x09e699dd9adfa5ac, + }, + { + 0x0de5c357bff57107, + 0x0a0db4ae6b1a10b2, + 0xe256bb67b3b3cd8d, + 0x8ad456574e9db24f, + 0x0443915f50fd4179, + 0x098c4bf7de8b6375, + }, + { + 0xe6b0617e7dd929c7, + 0xfe6e37d442537375, + 0x1dafdeda137a489e, + 0xe4efd1ad3f767ceb, + 0x4a51d8667f0fe1cf, + 0x054fdf4bbf1d821c, + }, + { + 0x72db2a50658d767b, + 0x8abf91faa257b3d5, + 0xe969d6833764ab47, + 0x464170142a1009eb, + 0xb14f01aadb30be2f, + 0x18ae6a856f40715d, + }, + } + g1IsoXDen = []fp{ + { + 0xb962a077fdb0f945, + 0xa6a9740fefda13a0, + 0xc14d568c3ed6c544, + 0xb43fc37b908b133e, + 0x9c0b3ac929599016, + 0x0165aa6c93ad115f, + }, + { + 0x23279a3ba506c1d9, + 0x92cfca0a9465176a, + 0x3b294ab13755f0ff, + 0x116dda1c5070ae93, + 0xed4530924cec2045, + 0x083383d6ed81f1ce, + }, + { + 0x9885c2a6449fecfc, + 0x4a2b54ccd37733f0, + 0x17da9ffd8738c142, + 0xa0fba72732b3fafd, + 0xff364f36e54b6812, + 0x0f29c13c660523e2, + }, + { + 0xe349cc118278f041, + 0xd487228f2f3204fb, + 0xc9d325849ade5150, + 0x43a92bd69c15c2df, + 0x1c2c7844bc417be4, + 0x12025184f407440c, + }, + { + 0x587f65ae6acb057b, + 0x1444ef325140201f, + 0xfbf995e71270da49, + 0xccda066072436a42, + 0x7408904f0f186bb2, + 0x13b93c63edf6c015, + }, + { + 0xfb918622cd141920, + 0x4a4c64423ecaddb4, + 0x0beb232927f7fb26, + 0x30f94df6f83a3dc2, + 0xaeedd424d780f388, + 0x06cc402dd594bbeb, + }, + { + 0xd41f761151b23f8f, + 0x32a92465435719b3, + 0x64f436e888c62cb9, + 0xdf70a9a1f757c6e4, + 0x6933a38d5b594c81, + 0x0c6f7f7237b46606, + }, + { + 0x693c08747876c8f7, + 0x22c9850bf9cf80f0, + 0x8e9071dab950c124, + 0x89bc62d61c7baf23, + 0xbc6be2d8dad57c23, + 0x17916987aa14a122, + }, + { + 0x1be3ff439c1316fd, + 0x9965243a7571dfa7, + 0xc7f7f62962f5cd81, + 0x32c6aa9af394361c, + 0xbbc2ee18e1c227f4, + 0x0c102cbac531bb34, + }, + { + 0x997614c97bacbf07, + 0x61f86372b99192c0, + 0x5b8c95fc14353fc3, + 0xca2b066c2a87492f, + 0x16178f5bbf698711, + 0x12a6dcd7f0f4e0e8, + }, + { + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + }, + } + g1IsoYNum = []fp{ + { + 0x2b567ff3e2837267, + 0x1d4d9e57b958a767, + 0xce028fea04bd7373, + 0xcc31a30a0b6cd3df, + 0x7d7b18a682692693, + 0x0d300744d42a0310, + }, + { + 0x99c2555fa542493f, + 0xfe7f53cc4874f878, + 0x5df0608b8f97608a, + 0x14e03832052b49c8, + 0x706326a6957dd5a4, + 0x0a8dadd9c2414555, + }, + { + 0x13d942922a5cf63a, + 0x357e33e36e261e7d, + 0xcf05a27c8456088d, + 0x0000bd1de7ba50f0, + 0x83d0c7532f8c1fde, + 0x13f70bf38bbf2905, + }, + { + 0x5c57fd95bfafbdbb, + 0x28a359a65e541707, + 0x3983ceb4f6360b6d, + 0xafe19ff6f97e6d53, + 0xb3468f4550192bf7, + 0x0bb6cde49d8ba257, + }, + { + 0x590b62c7ff8a513f, + 0x314b4ce372cacefd, + 0x6bef32ce94b8a800, + 0x6ddf84a095713d5f, + 0x64eace4cb0982191, + 0x0386213c651b888d, + }, + { + 0xa5310a31111bbcdd, + 0xa14ac0f5da148982, + 0xf9ad9cc95423d2e9, + 0xaa6ec095283ee4a7, + 0xcf5b1f022e1c9107, + 0x01fddf5aed881793, + }, + { + 0x65a572b0d7a7d950, + 0xe25c2d8183473a19, + 0xc2fcebe7cb877dbd, + 0x05b2d36c769a89b0, + 0xba12961be86e9efb, + 0x07eb1b29c1dfde1f, + }, + { + 0x93e09572f7c4cd24, + 0x364e929076795091, + 0x8569467e68af51b5, + 0xa47da89439f5340f, + 0xf4fa918082e44d64, + 0x0ad52ba3e6695a79, + }, + { + 0x911429844e0d5f54, + 0xd03f51a3516bb233, + 0x3d587e5640536e66, + 0xfa86d2a3a9a73482, + 0xa90ed5adf1ed5537, + 0x149c9c326a5e7393, + }, + { + 0x462bbeb03c12921a, + 0xdc9af5fa0a274a17, + 0x9a558ebde836ebed, + 0x649ef8f11a4fae46, + 0x8100e1652b3cdc62, + 0x1862bd62c291dacb, + }, + { + 0x05c9b8ca89f12c26, + 0x0194160fa9b9ac4f, + 0x6a643d5a6879fa2c, + 0x14665bdd8846e19d, + 0xbb1d0d53af3ff6bf, + 0x12c7e1c3b28962e5, + }, + { + 0xb55ebf900b8a3e17, + 0xfedc77ec1a9201c4, + 0x1f07db10ea1a4df4, + 0x0dfbd15dc41a594d, + 0x389547f2334a5391, + 0x02419f98165871a4, + }, + { + 0xb416af000745fc20, + 0x8e563e9d1ea6d0f5, + 0x7c763e17763a0652, + 0x01458ef0159ebbef, + 0x8346fe421f96bb13, + 0x0d2d7b829ce324d2, + }, + { + 0x93096bb538d64615, + 0x6f2a2619951d823a, + 0x8f66b3ea59514fa4, + 0xf563e63704f7092f, + 0x724b136c4cf2d9fa, + 0x046959cfcfd0bf49, + }, + { + 0xea748d4b6e405346, + 0x91e9079c2c02d58f, + 0x41064965946d9b59, + 0xa06731f1d2bbe1ee, + 0x07f897e267a33f1b, + 0x1017290919210e5f, + }, + { + 0x872aa6c17d985097, + 0xeecc53161264562a, + 0x07afe37afff55002, + 0x54759078e5be6838, + 0xc4b92d15db8acca8, + 0x106d87d1b51d13b9, + }, + } + g1IsoYDen = []fp{ + { + 0xeb6c359d47e52b1c, + 0x18ef5f8a10634d60, + 0xddfa71a0889d5b7e, + 0x723e71dcc5fc1323, + 0x52f45700b70d5c69, + 0x0a8b981ee47691f1, + }, + { + 0x616a3c4f5535b9fb, + 0x6f5f037395dbd911, + 0xf25f4cc5e35c65da, + 0x3e50dffea3c62658, + 0x6a33dca523560776, + 0x0fadeff77b6bfe3e, + }, + { + 0x2be9b66df470059c, + 0x24a2c159a3d36742, + 0x115dbe7ad10c2a37, + 0xb6634a652ee5884d, + 0x04fe8bb2b8d81af4, + 0x01c2a7a256fe9c41, + }, + { + 0xf27bf8ef3b75a386, + 0x898b367476c9073f, + 0x24482e6b8c2f4e5f, + 0xc8e0bbd6fe110806, + 0x59b0c17f7631448a, + 0x11037cd58b3dbfbd, + }, + { + 0x31c7912ea267eec6, + 0x1dbf6f1c5fcdb700, + 0xd30d4fe3ba86fdb1, + 0x3cae528fbee9a2a4, + 0xb1cce69b6aa9ad9a, + 0x044393bb632d94fb, + }, + { + 0xc66ef6efeeb5c7e8, + 0x9824c289dd72bb55, + 0x71b1a4d2f119981d, + 0x104fc1aafb0919cc, + 0x0e49df01d942a628, + 0x096c3a09773272d4, + }, + { + 0x9abc11eb5fadeff4, + 0x32dca50a885728f0, + 0xfb1fa3721569734c, + 0xc4b76271ea6506b3, + 0xd466a75599ce728e, + 0x0c81d4645f4cb6ed, + }, + { + 0x4199f10e5b8be45b, + 0xda64e495b1e87930, + 0xcb353efe9b33e4ff, + 0x9e9efb24aa6424c6, + 0xf08d33680a237465, + 0x0d3378023e4c7406, + }, + { + 0x7eb4ae92ec74d3a5, + 0xc341b4aa9fac3497, + 0x5be603899e907687, + 0x03bfd9cca75cbdeb, + 0x564c2935a96bfa93, + 0x0ef3c33371e2fdb5, + }, + { + 0x7ee91fd449f6ac2e, + 0xe5d5bd5cb9357a30, + 0x773a8ca5196b1380, + 0xd0fda172174ed023, + 0x6cb95e0fa776aead, + 0x0d22d5a40cec7cff, + }, + { + 0xf727e09285fd8519, + 0xdc9d55a83017897b, + 0x7549d8bd057894ae, + 0x178419613d90d8f8, + 0xfce95ebdeb5b490a, + 0x0467ffaef23fc49e, + }, + { + 0xc1769e6a7c385f1b, + 0x79bc930deac01c03, + 0x5461c75a23ede3b5, + 0x6e20829e5c230c45, + 0x828e0f1e772a53cd, + 0x116aefa749127bff, + }, + { + 0x101c10bf2744c10a, + 0xbbf18d053a6a3154, + 0xa0ecf39ef026f602, + 0xfc009d4996dc5153, + 0xb9000209d5bd08d3, + 0x189e5fe4470cd73c, + }, + { + 0x7ebd546ca1575ed2, + 0xe47d5a981d081b55, + 0x57b2b625b6d4ca21, + 0xb0a1ba04228520cc, + 0x98738983c2107ff3, + 0x13dddbc4799d81d6, + }, + { + 0x09319f2e39834935, + 0x039e952cbdb05c21, + 0x55ba77a9a2f76493, + 0xfd04e3dfc6086467, + 0xfb95832e7d78742e, + 0x0ef9c24eccaf5e0e, + }, + { + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + }, + } +) + +// G1 is a point in g1 +type G1 struct { + x, y, z fp +} + +// Random creates a random point on the curve +// from the specified reader +func (g1 *G1) Random(reader io.Reader) (*G1, error) { + var seed [native.WideFieldBytes]byte + n, err := reader.Read(seed[:]) + + if err != nil { + return nil, errors.Wrap(err, "random could not read from stream") + } + if n != native.WideFieldBytes { + return nil, fmt.Errorf("insufficient bytes read %d when %d are needed", n, WideFieldBytes) + } + dst := []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_") + return g1.Hash(native.EllipticPointHasherSha256(), seed[:], dst), nil +} + +// Hash uses the hasher to map bytes to a valid point +func (g1 *G1) Hash(hash *native.EllipticPointHasher, msg, dst []byte) *G1 { + var u []byte + var u0, u1 fp + var r0, r1, q0, q1 G1 + + switch hash.Type() { + case native.XMD: + u = native.ExpandMsgXmd(hash, msg, dst, 128) + case native.XOF: + u = native.ExpandMsgXof(hash, msg, dst, 128) + } + + var buf [WideFieldBytes]byte + copy(buf[:64], internal.ReverseScalarBytes(u[:64])) + u0.SetBytesWide(&buf) + copy(buf[:64], internal.ReverseScalarBytes(u[64:])) + u1.SetBytesWide(&buf) + + r0.osswu3mod4(&u0) + r1.osswu3mod4(&u1) + q0.isogenyMap(&r0) + q1.isogenyMap(&r1) + g1.Add(&q0, &q1) + return g1.ClearCofactor(g1) +} + +// Identity returns the identity point +func (g1 *G1) Identity() *G1 { + g1.x.SetZero() + g1.y.SetOne() + g1.z.SetZero() + return g1 +} + +// Generator returns the base point +func (g1 *G1) Generator() *G1 { + g1.x.Set(&g1x) + g1.y.Set(&g1y) + g1.z.SetOne() + return g1 +} + +// IsIdentity returns true if this point is at infinity +func (g1 *G1) IsIdentity() int { + return g1.z.IsZero() +} + +// IsOnCurve determines if this point represents a valid curve point +func (g1 *G1) IsOnCurve() int { + // Y^2 Z = X^3 + b Z^3 + var lhs, rhs, t fp + lhs.Square(&g1.y) + lhs.Mul(&lhs, &g1.z) + + rhs.Square(&g1.x) + rhs.Mul(&rhs, &g1.x) + t.Square(&g1.z) + t.Mul(&t, &g1.z) + t.Mul(&t, &curveG1B) + rhs.Add(&rhs, &t) + + return lhs.Equal(&rhs) +} + +// InCorrectSubgroup returns 1 if the point is torsion free, 0 otherwise +func (g1 *G1) InCorrectSubgroup() int { + var t G1 + t.multiply(g1, &fqModulusBytes) + return t.IsIdentity() +} + +// Add adds this point to another point. +func (g1 *G1) Add(arg1, arg2 *G1) *G1 { + // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf + var t0, t1, t2, t3, t4, x3, y3, z3 fp + + t0.Mul(&arg1.x, &arg2.x) + t1.Mul(&arg1.y, &arg2.y) + t2.Mul(&arg1.z, &arg2.z) + t3.Add(&arg1.x, &arg1.y) + t4.Add(&arg2.x, &arg2.y) + t3.Mul(&t3, &t4) + t4.Add(&t0, &t1) + t3.Sub(&t3, &t4) + t4.Add(&arg1.y, &arg1.z) + x3.Add(&arg2.y, &arg2.z) + t4.Mul(&t4, &x3) + x3.Add(&t1, &t2) + t4.Sub(&t4, &x3) + x3.Add(&arg1.x, &arg1.z) + y3.Add(&arg2.x, &arg2.z) + x3.Mul(&x3, &y3) + y3.Add(&t0, &t2) + y3.Sub(&x3, &y3) + x3.Double(&t0) + t0.Add(&t0, &x3) + t2.MulBy3b(&t2) + z3.Add(&t1, &t2) + t1.Sub(&t1, &t2) + y3.MulBy3b(&y3) + x3.Mul(&t4, &y3) + t2.Mul(&t3, &t1) + x3.Sub(&t2, &x3) + y3.Mul(&y3, &t0) + t1.Mul(&t1, &z3) + y3.Add(&t1, &y3) + t0.Mul(&t0, &t3) + z3.Mul(&z3, &t4) + z3.Add(&z3, &t0) + + g1.x.Set(&x3) + g1.y.Set(&y3) + g1.z.Set(&z3) + return g1 +} + +// Sub subtracts the two points +func (g1 *G1) Sub(arg1, arg2 *G1) *G1 { + var t G1 + t.Neg(arg2) + return g1.Add(arg1, &t) +} + +// Double this point +func (g1 *G1) Double(a *G1) *G1 { + // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf + var t0, t1, t2, x3, y3, z3 fp + + t0.Square(&a.y) + z3.Double(&t0) + z3.Double(&z3) + z3.Double(&z3) + t1.Mul(&a.y, &a.z) + t2.Square(&a.z) + t2.MulBy3b(&t2) + x3.Mul(&t2, &z3) + y3.Add(&t0, &t2) + z3.Mul(&t1, &z3) + t1.Double(&t2) + t2.Add(&t2, &t1) + t0.Sub(&t0, &t2) + y3.Mul(&t0, &y3) + y3.Add(&y3, &x3) + t1.Mul(&a.x, &a.y) + x3.Mul(&t0, &t1) + x3.Double(&x3) + + e := a.IsIdentity() + g1.x.CMove(&x3, t0.SetZero(), e) + g1.z.CMove(&z3, &t0, e) + g1.y.CMove(&y3, t0.SetOne(), e) + return g1 +} + +// Mul multiplies this point by the input scalar +func (g1 *G1) Mul(a *G1, s *native.Field) *G1 { + bytes := s.Bytes() + return g1.multiply(a, &bytes) +} + +func (g1 *G1) multiply(a *G1, bytes *[native.FieldBytes]byte) *G1 { + var p G1 + precomputed := [16]*G1{} + precomputed[0] = new(G1).Identity() + precomputed[1] = new(G1).Set(a) + for i := 2; i < 16; i += 2 { + precomputed[i] = new(G1).Double(precomputed[i>>1]) + precomputed[i+1] = new(G1).Add(precomputed[i], a) + } + p.Identity() + for i := 0; i < 256; i += 4 { + // Brouwer / windowing method. window size of 4. + for j := 0; j < 4; j++ { + p.Double(&p) + } + window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F + p.Add(&p, precomputed[window]) + } + return g1.Set(&p) +} + +// MulByX multiplies by BLS X using double and add +func (g1 *G1) MulByX(a *G1) *G1 { + // Skip first bit since its always zero + var s, t, r G1 + r.Identity() + t.Set(a) + + for x := paramX >> 1; x != 0; x >>= 1 { + t.Double(&t) + s.Add(&r, &t) + r.CMove(&r, &s, int(x&1)) + } + // Since BLS_X is negative, flip the sign + return g1.Neg(&r) +} + +// ClearCofactor multiplies by (1 - z), where z is the parameter of BLS12-381, which +// [suffices to clear](https://ia.cr/2019/403) the cofactor and map +// elliptic curve points to elements of G1. +func (g1 *G1) ClearCofactor(a *G1) *G1 { + var t G1 + t.MulByX(a) + return g1.Sub(a, &t) +} + +// Neg negates this point +func (g1 *G1) Neg(a *G1) *G1 { + g1.Set(a) + g1.y.CNeg(&a.y, -(a.IsIdentity() - 1)) + return g1 +} + +// Set copies a into g1 +func (g1 *G1) Set(a *G1) *G1 { + g1.x.Set(&a.x) + g1.y.Set(&a.y) + g1.z.Set(&a.z) + return g1 +} + +// BigInt returns the x and y as big.Ints in affine +func (g1 *G1) BigInt() (x, y *big.Int) { + var t G1 + t.ToAffine(g1) + x = t.x.BigInt() + y = t.y.BigInt() + return +} + +// SetBigInt creates a point from affine x, y +// and returns the point if it is on the curve +func (g1 *G1) SetBigInt(x, y *big.Int) (*G1, error) { + var xx, yy fp + var pp G1 + pp.x = *(xx.SetBigInt(x)) + pp.y = *(yy.SetBigInt(y)) + + if pp.x.IsZero()&pp.y.IsZero() == 1 { + pp.Identity() + return g1.Set(&pp), nil + } + + pp.z.SetOne() + + // If not the identity point and not on the curve then invalid + if (pp.IsOnCurve()&pp.InCorrectSubgroup())|(xx.IsZero()&yy.IsZero()) == 0 { + return nil, fmt.Errorf("invalid coordinates") + } + return g1.Set(&pp), nil +} + +// ToCompressed serializes this element into compressed form. +func (g1 *G1) ToCompressed() [FieldBytes]byte { + var out [FieldBytes]byte + var t G1 + t.ToAffine(g1) + xBytes := t.x.Bytes() + copy(out[:], internal.ReverseScalarBytes(xBytes[:])) + isInfinity := byte(g1.IsIdentity()) + // Compressed flag + out[0] |= 1 << 7 + // Is infinity + out[0] |= (1 << 6) & -isInfinity + // Sign of y only set if not infinity + out[0] |= (byte(t.y.LexicographicallyLargest()) << 5) & (isInfinity - 1) + return out +} + +// FromCompressed deserializes this element from compressed form. +func (g1 *G1) FromCompressed(input *[FieldBytes]byte) (*G1, error) { + var xFp, yFp fp + var x [FieldBytes]byte + var p G1 + compressedFlag := int((input[0] >> 7) & 1) + infinityFlag := int((input[0] >> 6) & 1) + sortFlag := int((input[0] >> 5) & 1) + + if compressedFlag != 1 { + return nil, errors.New("compressed flag must be set") + } + + if infinityFlag == 1 { + return g1.Identity(), nil + } + + copy(x[:], internal.ReverseScalarBytes(input[:])) + // Mask away the flag bits + x[FieldBytes-1] &= 0x1F + _, valid := xFp.SetBytes(&x) + + if valid != 1 { + return nil, errors.New("invalid bytes - not in field") + } + + yFp.Square(&xFp) + yFp.Mul(&yFp, &xFp) + yFp.Add(&yFp, &curveG1B) + + _, wasSquare := yFp.Sqrt(&yFp) + if wasSquare != 1 { + return nil, errors.New("point is not on the curve") + } + + yFp.CNeg(&yFp, yFp.LexicographicallyLargest()^sortFlag) + p.x.Set(&xFp) + p.y.Set(&yFp) + p.z.SetOne() + if p.InCorrectSubgroup() == 0 { + return nil, errors.New("point is not in correct subgroup") + } + return g1.Set(&p), nil +} + +// ToUncompressed serializes this element into uncompressed form. +func (g1 *G1) ToUncompressed() [WideFieldBytes]byte { + var out [WideFieldBytes]byte + var t G1 + t.ToAffine(g1) + xBytes := t.x.Bytes() + yBytes := t.y.Bytes() + copy(out[:FieldBytes], internal.ReverseScalarBytes(xBytes[:])) + copy(out[FieldBytes:], internal.ReverseScalarBytes(yBytes[:])) + isInfinity := byte(g1.IsIdentity()) + out[0] |= (1 << 6) & -isInfinity + return out +} + +// FromUncompressed deserializes this element from uncompressed form. +func (g1 *G1) FromUncompressed(input *[WideFieldBytes]byte) (*G1, error) { + var xFp, yFp fp + var t [FieldBytes]byte + var p G1 + infinityFlag := int((input[0] >> 6) & 1) + + if infinityFlag == 1 { + return g1.Identity(), nil + } + + copy(t[:], internal.ReverseScalarBytes(input[:FieldBytes])) + // Mask away top bits + t[FieldBytes-1] &= 0x1F + + _, valid := xFp.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - x not in field") + } + copy(t[:], internal.ReverseScalarBytes(input[FieldBytes:])) + _, valid = yFp.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - y not in field") + } + + p.x.Set(&xFp) + p.y.Set(&yFp) + p.z.SetOne() + + if p.IsOnCurve() == 0 { + return nil, errors.New("point is not on the curve") + } + if p.InCorrectSubgroup() == 0 { + return nil, errors.New("point is not in correct subgroup") + } + return g1.Set(&p), nil +} + +// ToAffine converts the point into affine coordinates +func (g1 *G1) ToAffine(a *G1) *G1 { + var wasInverted int + var zero, x, y, z fp + _, wasInverted = z.Invert(&a.z) + x.Mul(&a.x, &z) + y.Mul(&a.y, &z) + + g1.x.CMove(&zero, &x, wasInverted) + g1.y.CMove(&zero, &y, wasInverted) + g1.z.CMove(&zero, z.SetOne(), wasInverted) + return g1 +} + +// GetX returns the affine X coordinate +func (g1 *G1) GetX() *fp { + var t G1 + t.ToAffine(g1) + return &t.x +} + +// GetY returns the affine Y coordinate +func (g1 *G1) GetY() *fp { + var t G1 + t.ToAffine(g1) + return &t.y +} + +// Equal returns 1 if the two points are equal 0 otherwise. +func (g1 *G1) Equal(rhs *G1) int { + var x1, x2, y1, y2 fp + var e1, e2 int + + // This technique avoids inversions + x1.Mul(&g1.x, &rhs.z) + x2.Mul(&rhs.x, &g1.z) + + y1.Mul(&g1.y, &rhs.z) + y2.Mul(&rhs.y, &g1.z) + + e1 = g1.z.IsZero() + e2 = rhs.z.IsZero() + + // Both at infinity or coordinates are the same + return (e1 & e2) | (^e1 & ^e2)&x1.Equal(&x2)&y1.Equal(&y2) +} + +// CMove sets g1 = arg1 if choice == 0 and g1 = arg2 if choice == 1 +func (g1 *G1) CMove(arg1, arg2 *G1, choice int) *G1 { + g1.x.CMove(&arg1.x, &arg2.x, choice) + g1.y.CMove(&arg1.y, &arg2.y, choice) + g1.z.CMove(&arg1.z, &arg2.z, choice) + return g1 +} + +// SumOfProducts computes the multi-exponentiation for the specified +// points and scalars and stores the result in `g1`. +// Returns an error if the lengths of the arguments is not equal. +func (g1 *G1) SumOfProducts(points []*G1, scalars []*native.Field) (*G1, error) { + const Upper = 256 + const W = 4 + const Windows = Upper / W // careful--use ceiling division in case this doesn't divide evenly + var sum G1 + if len(points) != len(scalars) { + return nil, fmt.Errorf("length mismatch") + } + + bucketSize := 1 << W + windows := make([]G1, Windows) + bytes := make([][32]byte, len(scalars)) + buckets := make([]G1, bucketSize) + + for i := 0; i < len(windows); i++ { + windows[i].Identity() + } + + for i, scalar := range scalars { + bytes[i] = scalar.Bytes() + } + + for j := 0; j < len(windows); j++ { + for i := 0; i < bucketSize; i++ { + buckets[i].Identity() + } + + for i := 0; i < len(scalars); i++ { + // j*W to get the nibble + // >> 3 to convert to byte, / 8 + // (W * j & W) gets the nibble, mod W + // 1 << W - 1 to get the offset + index := bytes[i][j*W>>3] >> (W * j & W) & (1< 0; i-- { + sum.Add(&sum, &buckets[i]) + windows[j].Add(&windows[j], &sum) + } + } + + g1.Identity() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < W; j++ { + g1.Double(g1) + } + + g1.Add(g1, &windows[i]) + } + return g1, nil +} + +func (g1 *G1) osswu3mod4(u *fp) *G1 { + // Taken from section 8.8.1 in + // + var tv1, tv2, tv3, tv4, xd, x1n, x2n, gxd, gx1, y1, y2 fp + + // tv1 = u^2 + tv1.Square(u) + // tv3 = Z * tv1 + tv3.Mul(&oswwuMapZ, &tv1) + // tv2 = tv3^2 + tv2.Square(&tv3) + // xd = tv2 + tv3 + xd.Add(&tv2, &tv3) + // x1n = xd + 1 + x1n.Add(&xd, &r) + // x1n = x1n * B + x1n.Mul(&x1n, &osswuMapB) + // xd = -A * xd + xd.Mul(&negOsswuMapA, &xd) + // xd = CMOV(xd, Z * A, xd == 0) + xd.CMove(&xd, &oswwuMapXd1, xd.IsZero()) + // tv2 = xd^2 + tv2.Square(&xd) + + gxd.Mul(&tv2, &xd) + tv2.Mul(&tv2, &osswuMapA) + gx1.Square(&x1n) + gx1.Add(&gx1, &tv2) + gx1.Mul(&gx1, &x1n) + tv2.Mul(&osswuMapB, &gxd) + + gx1.Add(&gx1, &tv2) + tv4.Square(&gxd) + tv2.Mul(&gx1, &gxd) + tv4.Mul(&tv4, &tv2) + y1.pow(&tv4, &osswuMapC1) + y1.Mul(&y1, &tv2) + + x2n.Mul(&tv3, &x1n) + y2.Mul(&y1, &osswuMapC2) + y2.Mul(&y2, &tv1) + y2.Mul(&y2, u) + + tv2.Square(&y1) + tv2.Mul(&tv2, &gxd) + e2 := tv2.Equal(&gx1) + + x2n.CMove(&x2n, &x1n, e2) + y2.CMove(&y2, &y1, e2) + + e3 := u.Sgn0() ^ y2.Sgn0() + y2.CNeg(&y2, e3) + + g1.z.SetOne() + g1.y.Set(&y2) + _, _ = g1.x.Invert(&xd) + g1.x.Mul(&g1.x, &x2n) + return g1 +} + +func (g1 *G1) isogenyMap(a *G1) *G1 { + const Degree = 16 + var xs [Degree]fp + xs[0] = r + xs[1].Set(&a.x) + xs[2].Square(&a.x) + for i := 3; i < Degree; i++ { + xs[i].Mul(&xs[i-1], &a.x) + } + + xNum := computeKFp(xs[:], g1IsoXNum) + xDen := computeKFp(xs[:], g1IsoXDen) + yNum := computeKFp(xs[:], g1IsoYNum) + yDen := computeKFp(xs[:], g1IsoYDen) + + g1.x.Invert(&xDen) + g1.x.Mul(&g1.x, &xNum) + + g1.y.Invert(&yDen) + g1.y.Mul(&g1.y, &yNum) + g1.y.Mul(&g1.y, &a.y) + g1.z.SetOne() + return g1 +} + +func computeKFp(xxs []fp, k []fp) fp { + var xx, t fp + for i := range k { + xx.Add(&xx, t.Mul(&xxs[i], &k[i])) + } + return xx +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g2.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g2.go new file mode 100644 index 0000000000..f0b18ab892 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/g2.go @@ -0,0 +1,1123 @@ +package bls12381 + +import ( + "fmt" + "io" + "math/big" + + "github.com/pkg/errors" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var ( + g2x = fp2{ + A: fp{ + 0xf5f2_8fa2_0294_0a10, + 0xb3f5_fb26_87b4_961a, + 0xa1a8_93b5_3e2a_e580, + 0x9894_999d_1a3c_aee9, + 0x6f67_b763_1863_366b, + 0x0581_9192_4350_bcd7, + }, + B: fp{ + 0xa5a9_c075_9e23_f606, + 0xaaa0_c59d_bccd_60c3, + 0x3bb1_7e18_e286_7806, + 0x1b1a_b6cc_8541_b367, + 0xc2b6_ed0e_f215_8547, + 0x1192_2a09_7360_edf3, + }, + } + g2y = fp2{ + A: fp{ + 0x4c73_0af8_6049_4c4a, + 0x597c_fa1f_5e36_9c5a, + 0xe7e6_856c_aa0a_635a, + 0xbbef_b5e9_6e0d_495f, + 0x07d3_a975_f0ef_25a2, + 0x0083_fd8e_7e80_dae5, + }, + B: fp{ + 0xadc0_fc92_df64_b05d, + 0x18aa_270a_2b14_61dc, + 0x86ad_ac6a_3be4_eba0, + 0x7949_5c4e_c93d_a33a, + 0xe717_5850_a43c_caed, + 0x0b2b_c2a1_63de_1bf2, + }, + } + curveG2B = fp2{ + A: fp{ + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e, + }, + B: fp{ + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e, + }, + } + curveG23B = fp2{ + A: fp{ + 0x447600000027552e, + 0xdcb8009a43480020, + 0x6f7ee9ce4a6e8b59, + 0xb10330b7c0a95bc6, + 0x6140b1fcfb1e54b7, + 0x0381be097f0bb4e1, + }, + B: fp{ + 0x447600000027552e, + 0xdcb8009a43480020, + 0x6f7ee9ce4a6e8b59, + 0xb10330b7c0a95bc6, + 0x6140b1fcfb1e54b7, + 0x0381be097f0bb4e1, + }, + } + sswuMapA = fp2{ + A: fp{}, + B: fp{ + 0xe53a000003135242, + 0x01080c0fdef80285, + 0xe7889edbe340f6bd, + 0x0b51375126310601, + 0x02d6985717c744ab, + 0x1220b4e979ea5467, + }, + } + sswuMapB = fp2{ + A: fp{ + 0x22ea00000cf89db2, + 0x6ec832df71380aa4, + 0x6e1b94403db5a66e, + 0x75bf3c53a79473ba, + 0x3dd3a569412c0a34, + 0x125cdb5e74dc4fd1, + }, + B: fp{ + 0x22ea00000cf89db2, + 0x6ec832df71380aa4, + 0x6e1b94403db5a66e, + 0x75bf3c53a79473ba, + 0x3dd3a569412c0a34, + 0x125cdb5e74dc4fd1, + }, + } + sswuMapZ = fp2{ + A: fp{ + 0x87ebfffffff9555c, + 0x656fffe5da8ffffa, + 0x0fd0749345d33ad2, + 0xd951e663066576f4, + 0xde291a3d41e980d3, + 0x0815664c7dfe040d, + }, + B: fp{ + 0x43f5fffffffcaaae, + 0x32b7fff2ed47fffd, + 0x07e83a49a2e99d69, + 0xeca8f3318332bb7a, + 0xef148d1ea0f4c069, + 0x040ab3263eff0206, + }, + } + sswuMapZInv = fp2{ + A: fp{ + 0xacd0000000011110, + 0x9dd9999dc88ccccd, + 0xb5ca2ac9b76352bf, + 0xf1b574bcf4bc90ce, + 0x42dab41f28a77081, + 0x132fc6ac14cd1e12, + }, + B: fp{ + 0xe396ffffffff2223, + 0x4fbf332fcd0d9998, + 0x0c4bbd3c1aff4cc4, + 0x6b9c91267926ca58, + 0x29ae4da6aef7f496, + 0x10692e942f195791, + }, + } + swwuMapMbDivA = fp2{ + A: fp{ + 0x903c555555474fb3, + 0x5f98cc95ce451105, + 0x9f8e582eefe0fade, + 0xc68946b6aebbd062, + 0x467a4ad10ee6de53, + 0x0e7146f483e23a05, + }, + B: fp{ + 0x29c2aaaaaab85af8, + 0xbf133368e30eeefa, + 0xc7a27a7206cffb45, + 0x9dee04ce44c9425c, + 0x04a15ce53464ce83, + 0x0b8fcaf5b59dac95, + }, + } + + g2IsoXNum = []fp2{ + { + A: fp{ + 0x47f671c71ce05e62, + 0x06dd57071206393e, + 0x7c80cd2af3fd71a2, + 0x048103ea9e6cd062, + 0xc54516acc8d037f6, + 0x13808f550920ea41, + }, + B: fp{ + 0x47f671c71ce05e62, + 0x06dd57071206393e, + 0x7c80cd2af3fd71a2, + 0x048103ea9e6cd062, + 0xc54516acc8d037f6, + 0x13808f550920ea41, + }, + }, + { + A: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + B: fp{ + 0x5fe55555554c71d0, + 0x873fffdd236aaaa3, + 0x6a6b4619b26ef918, + 0x21c2888408874945, + 0x2836cda7028cabc5, + 0x0ac73310a7fd5abd, + }, + }, + { + A: fp{ + 0x0a0c5555555971c3, + 0xdb0c00101f9eaaae, + 0xb1fb2f941d797997, + 0xd3960742ef416e1c, + 0xb70040e2c20556f4, + 0x149d7861e581393b, + }, + B: fp{ + 0xaff2aaaaaaa638e8, + 0x439fffee91b55551, + 0xb535a30cd9377c8c, + 0x90e144420443a4a2, + 0x941b66d3814655e2, + 0x0563998853fead5e, + }, + }, + { + A: fp{ + 0x40aac71c71c725ed, + 0x190955557a84e38e, + 0xd817050a8f41abc3, + 0xd86485d4c87f6fb1, + 0x696eb479f885d059, + 0x198e1a74328002d2, + }, + B: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + } + g2IsoXDen = []fp2{ + { + A: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + B: fp{ + 0x1f3affffff13ab97, + 0xf25bfc611da3ff3e, + 0xca3757cb3819b208, + 0x3e6427366f8cec18, + 0x03977bc86095b089, + 0x04f69db13f39a952, + }, + }, + { + A: fp{ + 0x447600000027552e, + 0xdcb8009a43480020, + 0x6f7ee9ce4a6e8b59, + 0xb10330b7c0a95bc6, + 0x6140b1fcfb1e54b7, + 0x0381be097f0bb4e1, + }, + B: fp{ + 0x7588ffffffd8557d, + 0x41f3ff646e0bffdf, + 0xf7b1e8d2ac426aca, + 0xb3741acd32dbb6f8, + 0xe9daf5b9482d581f, + 0x167f53e0ba7431b8, + }, + }, + { + A: fp{ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + }, + B: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + } + g2IsoYNum = []fp2{ + { + A: fp{ + 0x96d8f684bdfc77be, + 0xb530e4f43b66d0e2, + 0x184a88ff379652fd, + 0x57cb23ecfae804e1, + 0x0fd2e39eada3eba9, + 0x08c8055e31c5d5c3, + }, + B: fp{ + 0x96d8f684bdfc77be, + 0xb530e4f43b66d0e2, + 0x184a88ff379652fd, + 0x57cb23ecfae804e1, + 0x0fd2e39eada3eba9, + 0x08c8055e31c5d5c3, + }, + }, + { + A: fp{ + 000000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + B: fp{ + 0xbf0a71c71c91b406, + 0x4d6d55d28b7638fd, + 0x9d82f98e5f205aee, + 0xa27aa27b1d1a18d5, + 0x02c3b2b2d2938e86, + 0x0c7d13420b09807f, + }, + }, + { + A: fp{ + 0xd7f9555555531c74, + 0x21cffff748daaaa8, + 0x5a9ad1866c9bbe46, + 0x4870a2210221d251, + 0x4a0db369c0a32af1, + 0x02b1ccc429ff56af, + }, + B: fp{ + 0xe205aaaaaaac8e37, + 0xfcdc000768795556, + 0x0c96011a8a1537dd, + 0x1c06a963f163406e, + 0x010df44c82a881e6, + 0x174f45260f808feb, + }, + }, + { + A: fp{ + 0xa470bda12f67f35c, + 0xc0fe38e23327b425, + 0xc9d3d0f2c6f0678d, + 0x1c55c9935b5a982e, + 0x27f6c0e2f0746764, + 0x117c5e6e28aa9054, + }, + B: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + } + g2IsoYDen = []fp2{ + { + A: fp{ + 0x0162fffffa765adf, + 0x8f7bea480083fb75, + 0x561b3c2259e93611, + 0x11e19fc1a9c875d5, + 0xca713efc00367660, + 0x03c6a03d41da1151, + }, + B: fp{ + 0x0162fffffa765adf, + 0x8f7bea480083fb75, + 0x561b3c2259e93611, + 0x11e19fc1a9c875d5, + 0xca713efc00367660, + 0x03c6a03d41da1151, + }, + }, + { + A: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + B: fp{ + 0x5db0fffffd3b02c5, + 0xd713f52358ebfdba, + 0x5ea60761a84d161a, + 0xbb2c75a34ea6c44a, + 0x0ac6735921c1119b, + 0x0ee3d913bdacfbf6, + }, + }, + { + A: fp{ + 0x66b10000003affc5, + 0xcb1400e764ec0030, + 0xa73e5eb56fa5d106, + 0x8984c913a0fe09a9, + 0x11e10afb78ad7f13, + 0x05429d0e3e918f52, + }, + B: fp{ + 0x534dffffffc4aae6, + 0x5397ff174c67ffcf, + 0xbff273eb870b251d, + 0xdaf2827152870915, + 0x393a9cbaca9e2dc3, + 0x14be74dbfaee5748, + }, + }, + { + A: fp{ + 0x760900000002fffd, + 0xebf4000bc40c0002, + 0x5f48985753c758ba, + 0x77ce585370525745, + 0x5c071a97a256ec6d, + 0x15f65ec3fa80e493, + }, + B: fp{ + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + } + + // 1 / ((u+1) ^ ((q-1)/3)) + psiCoeffX = fp2{ + A: fp{}, + B: fp{ + 0x890dc9e4867545c3, + 0x2af322533285a5d5, + 0x50880866309b7e2c, + 0xa20d1b8c7e881024, + 0x14e4f04fe2db9068, + 0x14e56d3f1564853a, + }, + } + // 1 / ((u+1) ^ (p-1)/2) + psiCoeffY = fp2{ + A: fp{ + 0x3e2f585da55c9ad1, + 0x4294213d86c18183, + 0x382844c88b623732, + 0x92ad2afd19103e18, + 0x1d794e4fac7cf0b9, + 0x0bd592fc7d825ec8, + }, + B: fp{ + 0x7bcfa7a25aa30fda, + 0xdc17dec12a927e7c, + 0x2f088dd86b4ebef1, + 0xd1ca2087da74d4a7, + 0x2da2596696cebc1d, + 0x0e2b7eedbbfd87d2, + }, + } + + // 1 / 2 ^ ((q-1)/3) + psi2CoeffX = fp2{ + A: fp{ + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x03f97d6e83d050d2, + 0x18f0206554638741, + }, + B: fp{}, + } +) + +// G2 is a point in g2 +type G2 struct { + x, y, z fp2 +} + +// Random creates a random point on the curve +// from the specified reader +func (g2 *G2) Random(reader io.Reader) (*G2, error) { + var seed [native.WideFieldBytes]byte + n, err := reader.Read(seed[:]) + + if err != nil { + return nil, errors.Wrap(err, "random could not read from stream") + } + if n != native.WideFieldBytes { + return nil, fmt.Errorf("insufficient bytes read %d when %d are needed", n, WideFieldBytes) + } + dst := []byte("BLS12381G2_XMD:SHA-256_SSWU_RO_") + return g2.Hash(native.EllipticPointHasherSha256(), seed[:], dst), nil +} + +// Hash uses the hasher to map bytes to a valid point +func (g2 *G2) Hash(hash *native.EllipticPointHasher, msg, dst []byte) *G2 { + var u []byte + var u0, u1 fp2 + var r0, r1, q0, q1 G2 + + switch hash.Type() { + case native.XMD: + u = native.ExpandMsgXmd(hash, msg, dst, 256) + case native.XOF: + u = native.ExpandMsgXof(hash, msg, dst, 256) + } + + var buf [96]byte + copy(buf[:64], internal.ReverseScalarBytes(u[:64])) + u0.A.SetBytesWide(&buf) + copy(buf[:64], internal.ReverseScalarBytes(u[64:128])) + u0.B.SetBytesWide(&buf) + copy(buf[:64], internal.ReverseScalarBytes(u[128:192])) + u1.A.SetBytesWide(&buf) + copy(buf[:64], internal.ReverseScalarBytes(u[192:])) + u1.B.SetBytesWide(&buf) + + r0.sswu(&u0) + r1.sswu(&u1) + q0.isogenyMap(&r0) + q1.isogenyMap(&r1) + g2.Add(&q0, &q1) + return g2.ClearCofactor(g2) +} + +// Identity returns the identity point +func (g2 *G2) Identity() *G2 { + g2.x.SetZero() + g2.y.SetOne() + g2.z.SetZero() + return g2 +} + +// Generator returns the base point +func (g2 *G2) Generator() *G2 { + g2.x.Set(&g2x) + g2.y.Set(&g2y) + g2.z.SetOne() + return g2 +} + +// IsIdentity returns true if this point is at infinity +func (g2 *G2) IsIdentity() int { + return g2.z.IsZero() +} + +// IsOnCurve determines if this point represents a valid curve point +func (g2 *G2) IsOnCurve() int { + // Y^2 Z = X^3 + b Z^3 + var lhs, rhs, t fp2 + lhs.Square(&g2.y) + lhs.Mul(&lhs, &g2.z) + + rhs.Square(&g2.x) + rhs.Mul(&rhs, &g2.x) + t.Square(&g2.z) + t.Mul(&t, &g2.z) + t.Mul(&t, &curveG2B) + rhs.Add(&rhs, &t) + + return lhs.Equal(&rhs) +} + +// InCorrectSubgroup returns 1 if the point is torsion free, 0 otherwise +func (g2 *G2) InCorrectSubgroup() int { + var t G2 + t.multiply(g2, &fqModulusBytes) + return t.IsIdentity() +} + +// Add adds this point to another point. +func (g2 *G2) Add(arg1, arg2 *G2) *G2 { + // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf + var t0, t1, t2, t3, t4, x3, y3, z3 fp2 + + t0.Mul(&arg1.x, &arg2.x) + t1.Mul(&arg1.y, &arg2.y) + t2.Mul(&arg1.z, &arg2.z) + t3.Add(&arg1.x, &arg1.y) + t4.Add(&arg2.x, &arg2.y) + t3.Mul(&t3, &t4) + t4.Add(&t0, &t1) + t3.Sub(&t3, &t4) + t4.Add(&arg1.y, &arg1.z) + x3.Add(&arg2.y, &arg2.z) + t4.Mul(&t4, &x3) + x3.Add(&t1, &t2) + t4.Sub(&t4, &x3) + x3.Add(&arg1.x, &arg1.z) + y3.Add(&arg2.x, &arg2.z) + x3.Mul(&x3, &y3) + y3.Add(&t0, &t2) + y3.Sub(&x3, &y3) + x3.Double(&t0) + t0.Add(&t0, &x3) + t2.MulBy3b(&t2) + z3.Add(&t1, &t2) + t1.Sub(&t1, &t2) + y3.MulBy3b(&y3) + x3.Mul(&t4, &y3) + t2.Mul(&t3, &t1) + x3.Sub(&t2, &x3) + y3.Mul(&y3, &t0) + t1.Mul(&t1, &z3) + y3.Add(&t1, &y3) + t0.Mul(&t0, &t3) + z3.Mul(&z3, &t4) + z3.Add(&z3, &t0) + + g2.x.Set(&x3) + g2.y.Set(&y3) + g2.z.Set(&z3) + return g2 +} + +// Sub subtracts the two points +func (g2 *G2) Sub(arg1, arg2 *G2) *G2 { + var t G2 + t.Neg(arg2) + return g2.Add(arg1, &t) +} + +// Double this point +func (g2 *G2) Double(a *G2) *G2 { + // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf + var t0, t1, t2, x3, y3, z3 fp2 + + t0.Square(&a.y) + z3.Double(&t0) + z3.Double(&z3) + z3.Double(&z3) + t1.Mul(&a.y, &a.z) + t2.Square(&a.z) + t2.MulBy3b(&t2) + x3.Mul(&t2, &z3) + y3.Add(&t0, &t2) + z3.Mul(&t1, &z3) + t1.Double(&t2) + t2.Add(&t2, &t1) + t0.Sub(&t0, &t2) + y3.Mul(&t0, &y3) + y3.Add(&y3, &x3) + t1.Mul(&a.x, &a.y) + x3.Mul(&t0, &t1) + x3.Double(&x3) + + e := a.IsIdentity() + g2.x.CMove(&x3, t0.SetZero(), e) + g2.z.CMove(&z3, &t0, e) + g2.y.CMove(&y3, t0.SetOne(), e) + return g2 +} + +// Mul multiplies this point by the input scalar +func (g2 *G2) Mul(a *G2, s *native.Field) *G2 { + bytes := s.Bytes() + return g2.multiply(a, &bytes) +} + +func (g2 *G2) multiply(a *G2, bytes *[native.FieldBytes]byte) *G2 { + var p G2 + precomputed := [16]*G2{} + precomputed[0] = new(G2).Identity() + precomputed[1] = new(G2).Set(a) + for i := 2; i < 16; i += 2 { + precomputed[i] = new(G2).Double(precomputed[i>>1]) + precomputed[i+1] = new(G2).Add(precomputed[i], a) + } + p.Identity() + for i := 0; i < 256; i += 4 { + // Brouwer / windowing method. window size of 4. + for j := 0; j < 4; j++ { + p.Double(&p) + } + window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F + p.Add(&p, precomputed[window]) + } + return g2.Set(&p) +} + +// MulByX multiplies by BLS X using double and add +func (g2 *G2) MulByX(a *G2) *G2 { + // Skip first bit since its always zero + var s, t, r G2 + r.Identity() + t.Set(a) + + for x := paramX >> 1; x != 0; x >>= 1 { + t.Double(&t) + s.Add(&r, &t) + r.CMove(&r, &s, int(x&1)) + } + // Since BLS_X is negative, flip the sign + return g2.Neg(&r) +} + +// ClearCofactor using [Budroni-Pintore](https://ia.cr/2017/419). +// This is equivalent to multiplying by h_{eff} = 3(z^2 - 1) * h_2 +// where h_2 is the cofactor of G_2 and z is the parameter of BLS12-381. +func (g2 *G2) ClearCofactor(a *G2) *G2 { + var t1, t2, t3, pt G2 + + t1.MulByX(a) + t2.psi(a) + + pt.Double(a) + pt.psi2(&pt) + + t3.Add(&t1, &t2) + t3.MulByX(&t3) + + pt.Add(&pt, &t3) + pt.Sub(&pt, &t1) + pt.Sub(&pt, &t2) + pt.Sub(&pt, a) + return g2.Set(&pt) +} + +// Neg negates this point +func (g2 *G2) Neg(a *G2) *G2 { + g2.Set(a) + g2.y.CNeg(&a.y, -(a.IsIdentity() - 1)) + return g2 +} + +// Set copies a into g2 +func (g2 *G2) Set(a *G2) *G2 { + g2.x.Set(&a.x) + g2.y.Set(&a.y) + g2.z.Set(&a.z) + return g2 +} + +// BigInt returns the x and y as big.Ints in affine +func (g2 *G2) BigInt() (x, y *big.Int) { + var t G2 + out := t.ToUncompressed() + x = new(big.Int).SetBytes(out[:WideFieldBytes]) + y = new(big.Int).SetBytes(out[WideFieldBytes:]) + return +} + +// SetBigInt creates a point from affine x, y +// and returns the point if it is on the curve +func (g2 *G2) SetBigInt(x, y *big.Int) (*G2, error) { + var tt [DoubleWideFieldBytes]byte + + if len(x.Bytes()) == 0 && len(y.Bytes()) == 0 { + return g2.Identity(), nil + } + x.FillBytes(tt[:WideFieldBytes]) + y.FillBytes(tt[WideFieldBytes:]) + + return g2.FromUncompressed(&tt) +} + +// ToCompressed serializes this element into compressed form. +func (g2 *G2) ToCompressed() [WideFieldBytes]byte { + var out [WideFieldBytes]byte + var t G2 + t.ToAffine(g2) + xABytes := t.x.A.Bytes() + xBBytes := t.x.B.Bytes() + copy(out[:FieldBytes], internal.ReverseScalarBytes(xBBytes[:])) + copy(out[FieldBytes:], internal.ReverseScalarBytes(xABytes[:])) + isInfinity := byte(g2.IsIdentity()) + // Compressed flag + out[0] |= 1 << 7 + // Is infinity + out[0] |= (1 << 6) & -isInfinity + // Sign of y only set if not infinity + out[0] |= (byte(t.y.LexicographicallyLargest()) << 5) & (isInfinity - 1) + return out +} + +// FromCompressed deserializes this element from compressed form. +func (g2 *G2) FromCompressed(input *[WideFieldBytes]byte) (*G2, error) { + var xFp, yFp fp2 + var xA, xB [FieldBytes]byte + var p G2 + compressedFlag := int((input[0] >> 7) & 1) + infinityFlag := int((input[0] >> 6) & 1) + sortFlag := int((input[0] >> 5) & 1) + + if compressedFlag != 1 { + return nil, errors.New("compressed flag must be set") + } + + if infinityFlag == 1 { + return g2.Identity(), nil + } + + copy(xB[:], internal.ReverseScalarBytes(input[:FieldBytes])) + copy(xA[:], internal.ReverseScalarBytes(input[FieldBytes:])) + // Mask away the flag bits + xB[FieldBytes-1] &= 0x1F + _, validA := xFp.A.SetBytes(&xA) + _, validB := xFp.B.SetBytes(&xB) + + if validA&validB != 1 { + return nil, errors.New("invalid bytes - not in field") + } + + // Recover a y-coordinate given x by y = sqrt(x^3 + 4) + yFp.Square(&xFp) + yFp.Mul(&yFp, &xFp) + yFp.Add(&yFp, &curveG2B) + + _, wasSquare := yFp.Sqrt(&yFp) + if wasSquare != 1 { + return nil, errors.New("point is not on the curve") + } + + yFp.CNeg(&yFp, yFp.LexicographicallyLargest()^sortFlag) + p.x.Set(&xFp) + p.y.Set(&yFp) + p.z.SetOne() + if p.InCorrectSubgroup() == 0 { + return nil, errors.New("point is not in correct subgroup") + } + return g2.Set(&p), nil +} + +// ToUncompressed serializes this element into uncompressed form. +func (g2 *G2) ToUncompressed() [DoubleWideFieldBytes]byte { + var out [DoubleWideFieldBytes]byte + var t G2 + t.ToAffine(g2) + bytes := t.x.B.Bytes() + copy(out[:FieldBytes], internal.ReverseScalarBytes(bytes[:])) + bytes = t.x.A.Bytes() + copy(out[FieldBytes:WideFieldBytes], internal.ReverseScalarBytes(bytes[:])) + bytes = t.y.B.Bytes() + copy(out[WideFieldBytes:WideFieldBytes+FieldBytes], internal.ReverseScalarBytes(bytes[:])) + bytes = t.y.A.Bytes() + copy(out[WideFieldBytes+FieldBytes:], internal.ReverseScalarBytes(bytes[:])) + isInfinity := byte(g2.IsIdentity()) + out[0] |= (1 << 6) & -isInfinity + return out +} + +// FromUncompressed deserializes this element from uncompressed form. +func (g2 *G2) FromUncompressed(input *[DoubleWideFieldBytes]byte) (*G2, error) { + var a, b fp + var t [FieldBytes]byte + var p G2 + infinityFlag := int((input[0] >> 6) & 1) + + if infinityFlag == 1 { + return g2.Identity(), nil + } + + copy(t[:], internal.ReverseScalarBytes(input[:FieldBytes])) + // Mask away top bits + t[FieldBytes-1] &= 0x1F + + _, valid := b.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - x.B not in field") + } + copy(t[:], internal.ReverseScalarBytes(input[FieldBytes:WideFieldBytes])) + _, valid = a.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - x.A not in field") + } + + p.x.B.Set(&b) + p.x.A.Set(&a) + + copy(t[:], internal.ReverseScalarBytes(input[WideFieldBytes:WideFieldBytes+FieldBytes])) + _, valid = b.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - y.B not in field") + } + copy(t[:], internal.ReverseScalarBytes(input[FieldBytes+WideFieldBytes:])) + _, valid = a.SetBytes(&t) + if valid == 0 { + return nil, errors.New("invalid bytes - y.A not in field") + } + + p.y.B.Set(&b) + p.y.A.Set(&a) + p.z.SetOne() + + if p.IsOnCurve() == 0 { + return nil, errors.New("point is not on the curve") + } + if p.InCorrectSubgroup() == 0 { + return nil, errors.New("point is not in correct subgroup") + } + return g2.Set(&p), nil +} + +// ToAffine converts the point into affine coordinates +func (g2 *G2) ToAffine(a *G2) *G2 { + var wasInverted int + var zero, x, y, z fp2 + _, wasInverted = z.Invert(&a.z) + x.Mul(&a.x, &z) + y.Mul(&a.y, &z) + + g2.x.CMove(&zero, &x, wasInverted) + g2.y.CMove(&zero, &y, wasInverted) + g2.z.CMove(&zero, z.SetOne(), wasInverted) + return g2 +} + +// GetX returns the affine X coordinate +func (g2 *G2) GetX() *fp2 { + var t G2 + t.ToAffine(g2) + return &t.x +} + +// GetY returns the affine Y coordinate +func (g2 *G2) GetY() *fp2 { + var t G2 + t.ToAffine(g2) + return &t.y +} + +// Equal returns 1 if the two points are equal 0 otherwise. +func (g2 *G2) Equal(rhs *G2) int { + var x1, x2, y1, y2 fp2 + var e1, e2 int + + // This technique avoids inversions + x1.Mul(&g2.x, &rhs.z) + x2.Mul(&rhs.x, &g2.z) + + y1.Mul(&g2.y, &rhs.z) + y2.Mul(&rhs.y, &g2.z) + + e1 = g2.z.IsZero() + e2 = rhs.z.IsZero() + + // Both at infinity or coordinates are the same + return (e1 & e2) | (^e1 & ^e2)&x1.Equal(&x2)&y1.Equal(&y2) +} + +// CMove sets g2 = arg1 if choice == 0 and g2 = arg2 if choice == 1 +func (g2 *G2) CMove(arg1, arg2 *G2, choice int) *G2 { + g2.x.CMove(&arg1.x, &arg2.x, choice) + g2.y.CMove(&arg1.y, &arg2.y, choice) + g2.z.CMove(&arg1.z, &arg2.z, choice) + return g2 +} + +// SumOfProducts computes the multi-exponentiation for the specified +// points and scalars and stores the result in `g2`. +// Returns an error if the lengths of the arguments is not equal. +func (g2 *G2) SumOfProducts(points []*G2, scalars []*native.Field) (*G2, error) { + const Upper = 256 + const W = 4 + const Windows = Upper / W // careful--use ceiling division in case this doesn't divide evenly + var sum G2 + if len(points) != len(scalars) { + return nil, fmt.Errorf("length mismatch") + } + + bucketSize := 1 << W + windows := make([]G2, Windows) + bytes := make([][32]byte, len(scalars)) + buckets := make([]G2, bucketSize) + for i := 0; i < len(windows); i++ { + windows[i].Identity() + } + + for i, scalar := range scalars { + bytes[i] = scalar.Bytes() + } + + for j := 0; j < len(windows); j++ { + for i := 0; i < bucketSize; i++ { + buckets[i].Identity() + } + + for i := 0; i < len(scalars); i++ { + // j*W to get the nibble + // >> 3 to convert to byte, / 8 + // (W * j & W) gets the nibble, mod W + // 1 << W - 1 to get the offset + index := bytes[i][j*W>>3] >> (W * j & W) & (1< 0; i-- { + sum.Add(&sum, &buckets[i]) + windows[j].Add(&windows[j], &sum) + } + } + + g2.Identity() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < W; j++ { + g2.Double(g2) + } + + g2.Add(g2, &windows[i]) + } + return g2, nil +} + +func (g2 *G2) psi(a *G2) *G2 { + g2.x.FrobeniusMap(&a.x) + g2.y.FrobeniusMap(&a.y) + // z = frobenius(z) + g2.z.FrobeniusMap(&a.z) + + // x = frobenius(x)/((u+1)^((p-1)/3)) + g2.x.Mul(&g2.x, &psiCoeffX) + // y = frobenius(y)/(u+1)^((p-1)/2) + g2.y.Mul(&g2.y, &psiCoeffY) + + return g2 +} + +func (g2 *G2) psi2(a *G2) *G2 { + // x = frobenius^2(x)/2^((p-1)/3); note that q^2 is the order of the field. + g2.x.Mul(&a.x, &psi2CoeffX) + // y = -frobenius^2(y); note that q^2 is the order of the field. + g2.y.Neg(&a.y) + g2.z.Set(&a.z) + return g2 +} + +func (g2 *G2) sswu(u *fp2) *G2 { + /// simplified swu map for q = 9 mod 16 where AB == 0 + // + var tv1, tv2, x1, x2, gx1, gx2, x, y, y2, t fp2 + + tv1.Square(u) + tv1.Mul(&tv1, &sswuMapZ) + + tv2.Square(&tv1) + + x1.Add(&tv1, &tv2) + x1.Invert(&x1) + x1.Add(&x1, (&fp2{}).SetOne()) + x1.CMove(&x1, &sswuMapZInv, x1.IsZero()) + x1.Mul(&x1, &swwuMapMbDivA) + + gx1.Square(&x1) + gx1.Add(&gx1, &sswuMapA) + gx1.Mul(&gx1, &x1) + gx1.Add(&gx1, &sswuMapB) + + x2.Mul(&tv1, &x1) + + tv2.Mul(&tv2, &tv1) + + gx2.Mul(&gx1, &tv2) + + _, e2 := t.Sqrt(&gx1) + + x.CMove(&x2, &x1, e2) + y2.CMove(&gx2, &gx1, e2) + + y.Sqrt(&y2) + + y.CNeg(&y, u.Sgn0()^y.Sgn0()) + g2.x.Set(&x) + g2.y.Set(&y) + g2.z.SetOne() + return g2 +} + +func (g2 *G2) isogenyMap(a *G2) *G2 { + const Degree = 4 + var xs [Degree]fp2 + xs[0].SetOne() + xs[1].Set(&a.x) + xs[2].Square(&a.x) + for i := 3; i < Degree; i++ { + xs[i].Mul(&xs[i-1], &a.x) + } + + xNum := computeKFp2(xs[:], g2IsoXNum) + xDen := computeKFp2(xs[:], g2IsoXDen) + yNum := computeKFp2(xs[:], g2IsoYNum) + yDen := computeKFp2(xs[:], g2IsoYDen) + + g2.x.Invert(&xDen) + g2.x.Mul(&g2.x, &xNum) + + g2.y.Invert(&yDen) + g2.y.Mul(&g2.y, &yNum) + g2.y.Mul(&g2.y, &a.y) + g2.z.SetOne() + return g2 +} + +func computeKFp2(xxs []fp2, k []fp2) fp2 { + var xx, t fp2 + for i := range k { + xx.Add(&xx, t.Mul(&xxs[i], &k[i])) + } + return xx +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/gt.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/gt.go new file mode 100644 index 0000000000..a04d666297 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/gt.go @@ -0,0 +1,434 @@ +package bls12381 + +import ( + "io" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +// GtFieldBytes is the number of bytes needed to represent this field +const GtFieldBytes = 576 + +// Gt is the target group +type Gt fp12 + +// Random generates a random field element +func (gt *Gt) Random(reader io.Reader) (*Gt, error) { + _, err := (*fp12)(gt).Random(reader) + return gt, err +} + +// FinalExponentiation performs a "final exponentiation" routine to convert the result +// of a Miller loop into an element of `Gt` with help of efficient squaring +// operation in the so-called `cyclotomic subgroup` of `Fq6` so that +// it can be compared with other elements of `Gt`. +func (gt *Gt) FinalExponentiation(a *Gt) *Gt { + var t0, t1, t2, t3, t4, t5, t6, t fp12 + t0.FrobeniusMap((*fp12)(a)) + t0.FrobeniusMap(&t0) + t0.FrobeniusMap(&t0) + t0.FrobeniusMap(&t0) + t0.FrobeniusMap(&t0) + t0.FrobeniusMap(&t0) + + // Shouldn't happen since we enforce `a` to be non-zero but just in case + _, wasInverted := t1.Invert((*fp12)(a)) + t2.Mul(&t0, &t1) + t1.Set(&t2) + t2.FrobeniusMap(&t2) + t2.FrobeniusMap(&t2) + t2.Mul(&t2, &t1) + t1.cyclotomicSquare(&t2) + t1.Conjugate(&t1) + + t3.cyclotomicExp(&t2) + t4.cyclotomicSquare(&t3) + t5.Mul(&t1, &t3) + t1.cyclotomicExp(&t5) + t0.cyclotomicExp(&t1) + t6.cyclotomicExp(&t0) + t6.Mul(&t6, &t4) + t4.cyclotomicExp(&t6) + t5.Conjugate(&t5) + t4.Mul(&t4, &t5) + t4.Mul(&t4, &t2) + t5.Conjugate(&t2) + t1.Mul(&t1, &t2) + t1.FrobeniusMap(&t1) + t1.FrobeniusMap(&t1) + t1.FrobeniusMap(&t1) + t6.Mul(&t6, &t5) + t6.FrobeniusMap(&t6) + t3.Mul(&t3, &t0) + t3.FrobeniusMap(&t3) + t3.FrobeniusMap(&t3) + t3.Mul(&t3, &t1) + t3.Mul(&t3, &t6) + t.Mul(&t3, &t4) + (*fp12)(gt).CMove((*fp12)(gt), &t, wasInverted) + return gt +} + +// IsZero returns 1 if gt == 0, 0 otherwise +func (gt *Gt) IsZero() int { + return (*fp12)(gt).IsZero() +} + +// IsOne returns 1 if gt == 1, 0 otherwise +func (gt *Gt) IsOne() int { + return (*fp12)(gt).IsOne() +} + +// SetOne gt = one +func (gt *Gt) SetOne() *Gt { + (*fp12)(gt).SetOne() + return gt +} + +// Set copies a into gt +func (gt *Gt) Set(a *Gt) *Gt { + gt.A.Set(&a.A) + gt.B.Set(&a.B) + return gt +} + +// Bytes returns the Gt field byte representation +func (gt *Gt) Bytes() [GtFieldBytes]byte { + var out [GtFieldBytes]byte + t := gt.A.A.A.Bytes() + copy(out[:FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.A.A.B.Bytes() + copy(out[FieldBytes:2*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.A.B.A.Bytes() + copy(out[2*FieldBytes:3*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.A.B.B.Bytes() + copy(out[3*FieldBytes:4*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.A.C.A.Bytes() + copy(out[4*FieldBytes:5*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.A.C.B.Bytes() + copy(out[5*FieldBytes:6*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.A.A.Bytes() + copy(out[6*FieldBytes:7*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.A.B.Bytes() + copy(out[7*FieldBytes:8*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.B.A.Bytes() + copy(out[8*FieldBytes:9*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.B.B.Bytes() + copy(out[9*FieldBytes:10*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.C.A.Bytes() + copy(out[10*FieldBytes:11*FieldBytes], internal.ReverseScalarBytes(t[:])) + t = gt.B.C.B.Bytes() + copy(out[11*FieldBytes:12*FieldBytes], internal.ReverseScalarBytes(t[:])) + + return out +} + +// SetBytes attempts to convert a big-endian byte representation of +// a scalar into a `Gt`, failing if the input is not canonical. +func (gt *Gt) SetBytes(input *[GtFieldBytes]byte) (*Gt, int) { + var t [FieldBytes]byte + var valid [12]int + copy(t[:], internal.ReverseScalarBytes(input[:FieldBytes])) + _, valid[0] = gt.A.A.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[FieldBytes:2*FieldBytes])) + _, valid[1] = gt.A.A.B.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[2*FieldBytes:3*FieldBytes])) + _, valid[2] = gt.A.B.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[3*FieldBytes:4*FieldBytes])) + _, valid[3] = gt.A.B.B.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[4*FieldBytes:5*FieldBytes])) + _, valid[4] = gt.A.C.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[5*FieldBytes:6*FieldBytes])) + _, valid[5] = gt.A.C.B.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[6*FieldBytes:7*FieldBytes])) + _, valid[6] = gt.B.A.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[7*FieldBytes:8*FieldBytes])) + _, valid[7] = gt.B.A.B.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[8*FieldBytes:9*FieldBytes])) + _, valid[8] = gt.B.B.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[9*FieldBytes:10*FieldBytes])) + _, valid[9] = gt.B.B.B.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[10*FieldBytes:11*FieldBytes])) + _, valid[10] = gt.B.C.A.SetBytes(&t) + copy(t[:], internal.ReverseScalarBytes(input[11*FieldBytes:12*FieldBytes])) + _, valid[11] = gt.B.C.B.SetBytes(&t) + + return gt, valid[0] & valid[1] & + valid[2] & valid[3] & + valid[4] & valid[5] & + valid[6] & valid[7] & + valid[8] & valid[9] & + valid[10] & valid[11] +} + +// Equal returns 1 if gt == rhs, 0 otherwise +func (gt *Gt) Equal(rhs *Gt) int { + return (*fp12)(gt).Equal((*fp12)(rhs)) +} + +// Generator returns the base point +func (gt *Gt) Generator() *Gt { + // pairing(&G1::generator(), &G2::generator()) + gt.Set((*Gt)(&fp12{ + A: fp6{ + A: fp2{ + A: fp{ + 0x1972e433a01f85c5, + 0x97d32b76fd772538, + 0xc8ce546fc96bcdf9, + 0xcef63e7366d40614, + 0xa611342781843780, + 0x13f3448a3fc6d825, + }, + B: fp{ + 0xd26331b02e9d6995, + 0x9d68a482f7797e7d, + 0x9c9b29248d39ea92, + 0xf4801ca2e13107aa, + 0xa16c0732bdbcb066, + 0x083ca4afba360478, + }, + }, + B: fp2{ + A: fp{ + 0x59e261db0916b641, + 0x2716b6f4b23e960d, + 0xc8e55b10a0bd9c45, + 0x0bdb0bd99c4deda8, + 0x8cf89ebf57fdaac5, + 0x12d6b7929e777a5e, + }, + B: fp{ + 0x5fc85188b0e15f35, + 0x34a06e3a8f096365, + 0xdb3126a6e02ad62c, + 0xfc6f5aa97d9a990b, + 0xa12f55f5eb89c210, + 0x1723703a926f8889, + }, + }, + C: fp2{ + A: fp{ + 0x93588f2971828778, + 0x43f65b8611ab7585, + 0x3183aaf5ec279fdf, + 0xfa73d7e18ac99df6, + 0x64e176a6a64c99b0, + 0x179fa78c58388f1f, + }, + B: fp{ + 0x672a0a11ca2aef12, + 0x0d11b9b52aa3f16b, + 0xa44412d0699d056e, + 0xc01d0177221a5ba5, + 0x66e0cede6c735529, + 0x05f5a71e9fddc339, + }, + }, + }, + B: fp6{ + A: fp2{ + A: fp{ + 0xd30a88a1b062c679, + 0x5ac56a5d35fc8304, + 0xd0c834a6a81f290d, + 0xcd5430c2da3707c7, + 0xf0c27ff780500af0, + 0x09245da6e2d72eae, + }, + B: fp{ + 0x9f2e0676791b5156, + 0xe2d1c8234918fe13, + 0x4c9e459f3c561bf4, + 0xa3e85e53b9d3e3c1, + 0x820a121e21a70020, + 0x15af618341c59acc, + }, + }, + B: fp2{ + A: fp{ + 0x7c95658c24993ab1, + 0x73eb38721ca886b9, + 0x5256d749477434bc, + 0x8ba41902ea504a8b, + 0x04a3d3f80c86ce6d, + 0x18a64a87fb686eaa, + }, + B: fp{ + 0xbb83e71bb920cf26, + 0x2a5277ac92a73945, + 0xfc0ee59f94f046a0, + 0x7158cdf3786058f7, + 0x7cc1061b82f945f6, + 0x03f847aa9fdbe567, + }, + }, + C: fp2{ + A: fp{ + 0x8078dba56134e657, + 0x1cd7ec9a43998a6e, + 0xb1aa599a1a993766, + 0xc9a0f62f0842ee44, + 0x8e159be3b605dffa, + 0x0c86ba0d4af13fc2, + }, + B: fp{ + 0xe80ff2a06a52ffb1, + 0x7694ca48721a906c, + 0x7583183e03b08514, + 0xf567afdd40cee4e2, + 0x9a6d96d2e526a5fc, + 0x197e9f49861f2242, + }, + }, + }, + })) + return gt +} + +// Add adds this value to another value. +func (gt *Gt) Add(arg1, arg2 *Gt) *Gt { + (*fp12)(gt).Mul((*fp12)(arg1), (*fp12)(arg2)) + return gt +} + +// Double this value +func (gt *Gt) Double(a *Gt) *Gt { + (*fp12)(gt).Square((*fp12)(a)) + return gt +} + +// Sub subtracts the two values +func (gt *Gt) Sub(arg1, arg2 *Gt) *Gt { + var t fp12 + t.Conjugate((*fp12)(arg2)) + (*fp12)(gt).Mul((*fp12)(arg1), &t) + return gt +} + +// Neg negates this value +func (gt *Gt) Neg(a *Gt) *Gt { + (*fp12)(gt).Conjugate((*fp12)(a)) + return gt +} + +// Mul multiplies this value by the input scalar +func (gt *Gt) Mul(a *Gt, s *native.Field) *Gt { + var f, p fp12 + f.Set((*fp12)(a)) + bytes := s.Bytes() + + precomputed := [16]fp12{} + precomputed[1].Set(&f) + for i := 2; i < 16; i += 2 { + precomputed[i].Square(&precomputed[i>>1]) + precomputed[i+1].Mul(&precomputed[i], &f) + } + for i := 0; i < 256; i += 4 { + // Brouwer / windowing method. window size of 4. + for j := 0; j < 4; j++ { + p.Square(&p) + } + window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F + p.Mul(&p, &precomputed[window]) + } + (*fp12)(gt).Set(&p) + return gt +} + +// Square this value +func (gt *Gt) Square(a *Gt) *Gt { + (*fp12)(gt).cyclotomicSquare((*fp12)(a)) + return gt +} + +// Invert this value +func (gt *Gt) Invert(a *Gt) (*Gt, int) { + _, wasInverted := (*fp12)(gt).Invert((*fp12)(a)) + return gt, wasInverted +} + +func fp4Square(a, b, arg1, arg2 *fp2) { + var t0, t1, t2 fp2 + + t0.Square(arg1) + t1.Square(arg2) + t2.MulByNonResidue(&t1) + a.Add(&t2, &t0) + t2.Add(arg1, arg2) + t2.Square(&t2) + t2.Sub(&t2, &t0) + b.Sub(&t2, &t1) +} + +func (f *fp12) cyclotomicSquare(a *fp12) *fp12 { + // Adaptation of Algorithm 5.5.4, Guide to Pairing-Based Cryptography + // Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions + // https://eprint.iacr.org/2009/565.pdf + var z0, z1, z2, z3, z4, z5, t0, t1, t2, t3 fp2 + z0.Set(&a.A.A) + z4.Set(&a.A.B) + z3.Set(&a.A.C) + z2.Set(&a.B.A) + z1.Set(&a.B.B) + z5.Set(&a.B.C) + + fp4Square(&t0, &t1, &z0, &z1) + z0.Sub(&t0, &z0) + z0.Double(&z0) + z0.Add(&z0, &t0) + + z1.Add(&t1, &z1) + z1.Double(&z1) + z1.Add(&z1, &t1) + + fp4Square(&t0, &t1, &z2, &z3) + fp4Square(&t2, &t3, &z4, &z5) + + z4.Sub(&t0, &z4) + z4.Double(&z4) + z4.Add(&z4, &t0) + + z5.Add(&z5, &t1) + z5.Double(&z5) + z5.Add(&z5, &t1) + + t0.MulByNonResidue(&t3) + z2.Add(&z2, &t0) + z2.Double(&z2) + z2.Add(&z2, &t0) + + z3.Sub(&t2, &z3) + z3.Double(&z3) + z3.Add(&z3, &t2) + + f.A.A.Set(&z0) + f.A.B.Set(&z4) + f.A.C.Set(&z3) + + f.B.A.Set(&z2) + f.B.B.Set(&z1) + f.B.C.Set(&z5) + return f +} + +func (f *fp12) cyclotomicExp(a *fp12) *fp12 { + var t fp12 + t.SetOne() + foundOne := 0 + + for i := 63; i >= 0; i-- { + b := int((paramX >> i) & 1) + if foundOne == 1 { + t.cyclotomicSquare(&t) + } else { + foundOne = b + } + if b == 1 { + t.Mul(&t, a) + } + } + f.Conjugate(&t) + return f +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/pairings.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/pairings.go new file mode 100644 index 0000000000..c01ef092af --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/bls12381/pairings.go @@ -0,0 +1,254 @@ +package bls12381 + +const coefficientsG2 = 68 + +type Engine struct { + pairs []pair +} + +type pair struct { + g1 G1 + g2 G2 +} + +type g2Prepared struct { + identity int + coefficients []coefficients +} + +type coefficients struct { + a, b, c fp2 +} + +func (c *coefficients) CMove(arg1, arg2 *coefficients, choice int) *coefficients { + c.a.CMove(&arg1.a, &arg2.a, choice) + c.b.CMove(&arg1.b, &arg2.b, choice) + c.c.CMove(&arg1.c, &arg2.c, choice) + return c +} + +// AddPair adds a pair of points to be paired +func (e *Engine) AddPair(g1 *G1, g2 *G2) *Engine { + var p pair + p.g1.ToAffine(g1) + p.g2.ToAffine(g2) + if p.g1.IsIdentity()|p.g2.IsIdentity() == 0 { + e.pairs = append(e.pairs, p) + } + return e +} + +// AddPairInvG1 adds a pair of points to be paired. G1 point is negated +func (e *Engine) AddPairInvG1(g1 *G1, g2 *G2) *Engine { + var p G1 + p.Neg(g1) + return e.AddPair(&p, g2) +} + +// AddPairInvG2 adds a pair of points to be paired. G2 point is negated +func (e *Engine) AddPairInvG2(g1 *G1, g2 *G2) *Engine { + var p G2 + p.Neg(g2) + return e.AddPair(g1, &p) +} + +func (e *Engine) Reset() *Engine { + e.pairs = []pair{} + return e +} + +func (e *Engine) Check() bool { + return e.pairing().IsOne() == 1 +} + +func (e *Engine) Result() *Gt { + return e.pairing() +} + +func (e *Engine) pairing() *Gt { + f := new(Gt).SetOne() + if len(e.pairs) == 0 { + return f + } + coeffs := e.computeCoeffs() + e.millerLoop((*fp12)(f), coeffs) + return f.FinalExponentiation(f) +} + +func (e *Engine) millerLoop(f *fp12, coeffs []g2Prepared) { + newF := new(fp12).SetZero() + found := 0 + cIdx := 0 + for i := 63; i >= 0; i-- { + x := int(((paramX >> 1) >> i) & 1) + if found == 0 { + found |= x + continue + } + + // doubling + for j, terms := range coeffs { + identity := e.pairs[j].g1.IsIdentity() | terms.identity + newF.Set(f) + ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1) + f.CMove(newF, f, identity) + } + cIdx++ + + if x == 1 { + // adding + for j, terms := range coeffs { + identity := e.pairs[j].g1.IsIdentity() | terms.identity + newF.Set(f) + ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1) + f.CMove(newF, f, identity) + } + cIdx++ + } + f.Square(f) + } + for j, terms := range coeffs { + identity := e.pairs[j].g1.IsIdentity() | terms.identity + newF.Set(f) + ell(newF, terms.coefficients[cIdx], &e.pairs[j].g1) + f.CMove(newF, f, identity) + } + f.Conjugate(f) +} + +func (e *Engine) computeCoeffs() []g2Prepared { + coeffs := make([]g2Prepared, len(e.pairs)) + for i, p := range e.pairs { + identity := p.g2.IsIdentity() + q := new(G2).Generator() + q.CMove(&p.g2, q, identity) + c := new(G2).Set(q) + cfs := make([]coefficients, coefficientsG2) + found := 0 + k := 0 + + for j := 63; j >= 0; j-- { + x := int(((paramX >> 1) >> j) & 1) + if found == 0 { + found |= x + continue + } + cfs[k] = doublingStep(c) + k++ + + if x == 1 { + cfs[k] = additionStep(c, q) + k++ + } + } + cfs[k] = doublingStep(c) + coeffs[i] = g2Prepared{ + coefficients: cfs, identity: identity, + } + } + return coeffs +} + +func ell(f *fp12, coeffs coefficients, p *G1) { + var x, y fp2 + x.A.Mul(&coeffs.a.A, &p.y) + x.B.Mul(&coeffs.a.B, &p.y) + y.A.Mul(&coeffs.b.A, &p.x) + y.B.Mul(&coeffs.b.B, &p.x) + f.MulByABD(f, &coeffs.c, &y, &x) +} + +func doublingStep(p *G2) coefficients { + // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf + var t0, t1, t2, t3, t4, t5, t6, zsqr fp2 + t0.Square(&p.x) + t1.Square(&p.y) + t2.Square(&t1) + t3.Add(&t1, &p.x) + t3.Square(&t3) + t3.Sub(&t3, &t0) + t3.Sub(&t3, &t2) + t3.Double(&t3) + t4.Double(&t0) + t4.Add(&t4, &t0) + t6.Add(&p.x, &t4) + t5.Square(&t4) + zsqr.Square(&p.z) + p.x.Sub(&t5, &t3) + p.x.Sub(&p.x, &t3) + p.z.Add(&p.z, &p.y) + p.z.Square(&p.z) + p.z.Sub(&p.z, &t1) + p.z.Sub(&p.z, &zsqr) + p.y.Sub(&t3, &p.x) + p.y.Mul(&p.y, &t4) + t2.Double(&t2) + t2.Double(&t2) + t2.Double(&t2) + p.y.Sub(&p.y, &t2) + t3.Mul(&t4, &zsqr) + t3.Double(&t3) + t3.Neg(&t3) + t6.Square(&t6) + t6.Sub(&t6, &t0) + t6.Sub(&t6, &t5) + t1.Double(&t1) + t1.Double(&t1) + t6.Sub(&t6, &t1) + t0.Mul(&p.z, &zsqr) + t0.Double(&t0) + + return coefficients{ + a: t0, b: t3, c: t6, + } +} + +func additionStep(r, q *G2) coefficients { + // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf + var zsqr, ysqr fp2 + var t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 fp2 + zsqr.Square(&r.z) + ysqr.Square(&q.y) + t0.Mul(&zsqr, &q.x) + t1.Add(&q.y, &r.z) + t1.Square(&t1) + t1.Sub(&t1, &ysqr) + t1.Sub(&t1, &zsqr) + t1.Mul(&t1, &zsqr) + t2.Sub(&t0, &r.x) + t3.Square(&t2) + t4.Double(&t3) + t4.Double(&t4) + t5.Mul(&t4, &t2) + t6.Sub(&t1, &r.y) + t6.Sub(&t6, &r.y) + t9.Mul(&t6, &q.x) + t7.Mul(&t4, &r.x) + r.x.Square(&t6) + r.x.Sub(&r.x, &t5) + r.x.Sub(&r.x, &t7) + r.x.Sub(&r.x, &t7) + r.z.Add(&r.z, &t2) + r.z.Square(&r.z) + r.z.Sub(&r.z, &zsqr) + r.z.Sub(&r.z, &t3) + t10.Add(&q.y, &r.z) + t8.Sub(&t7, &r.x) + t8.Mul(&t8, &t6) + t0.Mul(&r.y, &t5) + t0.Double(&t0) + r.y.Sub(&t8, &t0) + t10.Square(&t10) + t10.Sub(&t10, &ysqr) + zsqr.Square(&r.z) + t10.Sub(&t10, &zsqr) + t9.Double(&t9) + t9.Sub(&t9, &t10) + t10.Double(&r.z) + t6.Neg(&t6) + t1.Double(&t6) + + return coefficients{ + a: t10, b: t1, c: t9, + } +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/field.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/field.go new file mode 100644 index 0000000000..7ef2ace2f7 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/field.go @@ -0,0 +1,388 @@ +package native + +import ( + "encoding/binary" + "fmt" + "math/big" + + "github.com/coinbase/kryptology/internal" +) + +// FieldLimbs is the number of limbs needed to represent this field +const FieldLimbs = 4 + +// FieldBytes is the number of bytes needed to represent this field +const FieldBytes = 32 + +// WideFieldBytes is the number of bytes needed for safe conversion +// to this field to avoid bias when reduced +const WideFieldBytes = 64 + +// Field represents a field element +type Field struct { + // Value is the field elements value + Value [FieldLimbs]uint64 + // Params are the field parameters + Params *FieldParams + // Arithmetic are the field methods + Arithmetic FieldArithmetic +} + +// FieldParams are the field parameters +type FieldParams struct { + // R is 2^256 mod Modulus + R [FieldLimbs]uint64 + // R2 is 2^512 mod Modulus + R2 [FieldLimbs]uint64 + // R3 is 2^768 mod Modulus + R3 [FieldLimbs]uint64 + // Modulus of the field + Modulus [FieldLimbs]uint64 + // Modulus as big.Int + BiModulus *big.Int +} + +// FieldArithmetic are the methods that can be done on a field +type FieldArithmetic interface { + // ToMontgomery converts this field to montgomery form + ToMontgomery(out, arg *[FieldLimbs]uint64) + // FromMontgomery converts this field from montgomery form + FromMontgomery(out, arg *[FieldLimbs]uint64) + // Neg performs modular negation + Neg(out, arg *[FieldLimbs]uint64) + // Square performs modular square + Square(out, arg *[FieldLimbs]uint64) + // Mul performs modular multiplication + Mul(out, arg1, arg2 *[FieldLimbs]uint64) + // Add performs modular addition + Add(out, arg1, arg2 *[FieldLimbs]uint64) + // Sub performs modular subtraction + Sub(out, arg1, arg2 *[FieldLimbs]uint64) + // Sqrt performs modular square root + Sqrt(wasSquare *int, out, arg *[FieldLimbs]uint64) + // Invert performs modular inverse + Invert(wasInverted *int, out, arg *[FieldLimbs]uint64) + // FromBytes converts a little endian byte array into a field element + FromBytes(out *[FieldLimbs]uint64, arg *[FieldBytes]byte) + // ToBytes converts a field element to a little endian byte array + ToBytes(out *[FieldBytes]byte, arg *[FieldLimbs]uint64) + // Selectznz performs conditional select. + // selects arg1 if choice == 0 and arg2 if choice == 1 + Selectznz(out, arg1, arg2 *[FieldLimbs]uint64, choice int) +} + +// Cmp returns -1 if f < rhs +// 0 if f == rhs +// 1 if f > rhs +func (f *Field) Cmp(rhs *Field) int { + return cmpHelper(&f.Value, &rhs.Value) +} + +// cmpHelper returns -1 if lhs < rhs +// -1 if lhs == rhs +// 1 if lhs > rhs +// Public only for convenience for some internal implementations +func cmpHelper(lhs, rhs *[FieldLimbs]uint64) int { + gt := uint64(0) + lt := uint64(0) + for i := 3; i >= 0; i-- { + // convert to two 64-bit numbers where + // the leading bits are zeros and hold no meaning + // so rhs - fp actually means gt + // and fp - rhs actually means lt. + rhsH := rhs[i] >> 32 + rhsL := rhs[i] & 0xffffffff + lhsH := lhs[i] >> 32 + lhsL := lhs[i] & 0xffffffff + + // Check the leading bit + // if negative then fp > rhs + // if positive then fp < rhs + gt |= (rhsH - lhsH) >> 32 & 1 &^ lt + lt |= (lhsH - rhsH) >> 32 & 1 &^ gt + gt |= (rhsL - lhsL) >> 32 & 1 &^ lt + lt |= (lhsL - rhsL) >> 32 & 1 &^ gt + } + // Make the result -1 for <, 0 for =, 1 for > + return int(gt) - int(lt) +} + +// Equal returns 1 if f == rhs, 0 otherwise +func (f *Field) Equal(rhs *Field) int { + return equalHelper(&f.Value, &rhs.Value) +} + +func equalHelper(lhs, rhs *[FieldLimbs]uint64) int { + t := lhs[0] ^ rhs[0] + t |= lhs[1] ^ rhs[1] + t |= lhs[2] ^ rhs[2] + t |= lhs[3] ^ rhs[3] + return int(((int64(t) | int64(-t)) >> 63) + 1) +} + +// IsZero returns 1 if f == 0, 0 otherwise +func (f *Field) IsZero() int { + t := f.Value[0] + t |= f.Value[1] + t |= f.Value[2] + t |= f.Value[3] + return int(((int64(t) | int64(-t)) >> 63) + 1) +} + +// IsNonZero returns 1 if f != 0, 0 otherwise +func (f *Field) IsNonZero() int { + t := f.Value[0] + t |= f.Value[1] + t |= f.Value[2] + t |= f.Value[3] + return int(-((int64(t) | int64(-t)) >> 63)) +} + +// IsOne returns 1 if f == 1, 0 otherwise +func (f *Field) IsOne() int { + return equalHelper(&f.Value, &f.Params.R) +} + +// Set f = rhs +func (f *Field) Set(rhs *Field) *Field { + f.Value[0] = rhs.Value[0] + f.Value[1] = rhs.Value[1] + f.Value[2] = rhs.Value[2] + f.Value[3] = rhs.Value[3] + f.Params = rhs.Params + f.Arithmetic = rhs.Arithmetic + return f +} + +// SetUint64 f = rhs +func (f *Field) SetUint64(rhs uint64) *Field { + t := &[FieldLimbs]uint64{rhs, 0, 0, 0} + f.Arithmetic.ToMontgomery(&f.Value, t) + return f +} + +// SetOne f = r +func (f *Field) SetOne() *Field { + f.Value[0] = f.Params.R[0] + f.Value[1] = f.Params.R[1] + f.Value[2] = f.Params.R[2] + f.Value[3] = f.Params.R[3] + return f +} + +// SetZero f = 0 +func (f *Field) SetZero() *Field { + f.Value[0] = 0 + f.Value[1] = 0 + f.Value[2] = 0 + f.Value[3] = 0 + return f +} + +// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number. +// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/Fp.rs#L255 +// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits +// with the higher bits multiplied by 2^256. Thus, we perform two reductions +// +// 1. the lower bits are multiplied by r^2, as normal +// 2. the upper bits are multiplied by r^2 * 2^256 = r^3 +// +// and computing their sum in the field. It remains to see that arbitrary 256-bit +// numbers can be placed into Montgomery form safely using the reduction. The +// reduction works so long as the product is less than r=2^256 multiplied by +// the modulus. This holds because for any `c` smaller than the modulus, we have +// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the +// reduction always works so long as `c` is in the field; in this case it is either the +// constant `r2` or `r3`. +func (f *Field) SetBytesWide(input *[WideFieldBytes]byte) *Field { + d0 := [FieldLimbs]uint64{ + binary.LittleEndian.Uint64(input[:8]), + binary.LittleEndian.Uint64(input[8:16]), + binary.LittleEndian.Uint64(input[16:24]), + binary.LittleEndian.Uint64(input[24:32]), + } + d1 := [FieldLimbs]uint64{ + binary.LittleEndian.Uint64(input[32:40]), + binary.LittleEndian.Uint64(input[40:48]), + binary.LittleEndian.Uint64(input[48:56]), + binary.LittleEndian.Uint64(input[56:64]), + } + //f.Arithmetic.ToMontgomery(&d0, &d0) + //f.Arithmetic.Mul(&d1, &d1, &f.Params.R2) + //f.Arithmetic.Add(&f.Value, &d0, &d0) + // Convert to Montgomery form + tv1 := &[FieldLimbs]uint64{} + tv2 := &[FieldLimbs]uint64{} + // d0*r2 + d1*r3 + f.Arithmetic.Mul(tv1, &d0, &f.Params.R2) + f.Arithmetic.Mul(tv2, &d1, &f.Params.R3) + f.Arithmetic.Add(&f.Value, tv1, tv2) + return f +} + +// SetBytes attempts to convert a little endian byte representation +// of a scalar into a `Fp`, failing if input is not canonical +func (f *Field) SetBytes(input *[FieldBytes]byte) (*Field, error) { + d0 := [FieldLimbs]uint64{0, 0, 0, 0} + f.Arithmetic.FromBytes(&d0, input) + + if cmpHelper(&d0, &f.Params.Modulus) != -1 { + return nil, fmt.Errorf("invalid byte sequence") + } + return f.SetLimbs(&d0), nil +} + +// SetBigInt initializes an element from big.Int +// The value is reduced by the modulus +func (f *Field) SetBigInt(bi *big.Int) *Field { + var buffer [FieldBytes]byte + t := new(big.Int).Set(bi) + t.Mod(t, f.Params.BiModulus) + t.FillBytes(buffer[:]) + copy(buffer[:], internal.ReverseScalarBytes(buffer[:])) + _, _ = f.SetBytes(&buffer) + return f +} + +// SetRaw converts a raw array into a field element +// Assumes input is already in montgomery form +func (f *Field) SetRaw(input *[FieldLimbs]uint64) *Field { + f.Value[0] = input[0] + f.Value[1] = input[1] + f.Value[2] = input[2] + f.Value[3] = input[3] + return f +} + +// SetLimbs converts an array into a field element +// by converting to montgomery form +func (f *Field) SetLimbs(input *[FieldLimbs]uint64) *Field { + f.Arithmetic.ToMontgomery(&f.Value, input) + return f +} + +// Bytes converts this element into a byte representation +// in little endian byte order +func (f *Field) Bytes() [FieldBytes]byte { + var output [FieldBytes]byte + tv := &[FieldLimbs]uint64{} + f.Arithmetic.FromMontgomery(tv, &f.Value) + f.Arithmetic.ToBytes(&output, tv) + return output +} + +// BigInt converts this element into the big.Int struct +func (f *Field) BigInt() *big.Int { + buffer := f.Bytes() + return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:])) +} + +// Raw converts this element into the a [FieldLimbs]uint64 +func (f *Field) Raw() [FieldLimbs]uint64 { + res := &[FieldLimbs]uint64{} + f.Arithmetic.FromMontgomery(res, &f.Value) + return *res +} + +// Double this element +func (f *Field) Double(a *Field) *Field { + f.Arithmetic.Add(&f.Value, &a.Value, &a.Value) + return f +} + +// Square this element +func (f *Field) Square(a *Field) *Field { + f.Arithmetic.Square(&f.Value, &a.Value) + return f +} + +// Sqrt this element, if it exists. If true, then value +// is a square root. If false, value is a QNR +func (f *Field) Sqrt(a *Field) (*Field, bool) { + wasSquare := 0 + f.Arithmetic.Sqrt(&wasSquare, &f.Value, &a.Value) + return f, wasSquare == 1 +} + +// Invert this element i.e. compute the multiplicative inverse +// return false, zero if this element is zero. +func (f *Field) Invert(a *Field) (*Field, bool) { + wasInverted := 0 + f.Arithmetic.Invert(&wasInverted, &f.Value, &a.Value) + return f, wasInverted == 1 +} + +// Mul returns the result from multiplying this element by rhs +func (f *Field) Mul(lhs, rhs *Field) *Field { + f.Arithmetic.Mul(&f.Value, &lhs.Value, &rhs.Value) + return f +} + +// Sub returns the result from subtracting rhs from this element +func (f *Field) Sub(lhs, rhs *Field) *Field { + f.Arithmetic.Sub(&f.Value, &lhs.Value, &rhs.Value) + return f +} + +// Add returns the result from adding rhs to this element +func (f *Field) Add(lhs, rhs *Field) *Field { + f.Arithmetic.Add(&f.Value, &lhs.Value, &rhs.Value) + return f +} + +// Neg returns negation of this element +func (f *Field) Neg(input *Field) *Field { + f.Arithmetic.Neg(&f.Value, &input.Value) + return f +} + +// Exp raises base^exp +func (f *Field) Exp(base, exp *Field) *Field { + e := [FieldLimbs]uint64{} + f.Arithmetic.FromMontgomery(&e, &exp.Value) + Pow(&f.Value, &base.Value, &e, f.Params, f.Arithmetic) + return f +} + +// CMove sets f = lhs if choice == 0 and f = rhs if choice == 1 +func (f *Field) CMove(lhs, rhs *Field, choice int) *Field { + f.Arithmetic.Selectznz(&f.Value, &lhs.Value, &rhs.Value, choice) + return f +} + +// Pow raises base^exp. The result is written to out. +// Public only for convenience for some internal implementations +func Pow(out, base, exp *[FieldLimbs]uint64, params *FieldParams, arithmetic FieldArithmetic) { + res := [FieldLimbs]uint64{params.R[0], params.R[1], params.R[2], params.R[3]} + tmp := [FieldLimbs]uint64{} + + for i := len(exp) - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + arithmetic.Square(&res, &res) + arithmetic.Mul(&tmp, &res, base) + arithmetic.Selectznz(&res, &res, &tmp, int(exp[i]>>j)&1) + } + } + out[0] = res[0] + out[1] = res[1] + out[2] = res[2] + out[3] = res[3] +} + +// Pow2k raises arg to the power `2^k`. This result is written to out. +// Public only for convenience for some internal implementations +func Pow2k(out, arg *[FieldLimbs]uint64, k int, arithmetic FieldArithmetic) { + var t [FieldLimbs]uint64 + t[0] = arg[0] + t[1] = arg[1] + t[2] = arg[2] + t[3] = arg[3] + for i := 0; i < k; i++ { + arithmetic.Square(&t, &t) + } + + out[0] = t[0] + out[1] = t[1] + out[2] = t[2] + out[3] = t[3] +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/hash2field.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/hash2field.go new file mode 100644 index 0000000000..1d000253d3 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/hash2field.go @@ -0,0 +1,107 @@ +package native + +import ( + "hash" + + "golang.org/x/crypto/sha3" +) + +// OversizeDstSalt is the salt used to hash a dst over MaxDstLen +var OversizeDstSalt = []byte("H2C-OVERSIZE-DST-") + +// MaxDstLen the max size for dst in hash to curve +const MaxDstLen = 255 + +func getDomainXmd(h hash.Hash, domain []byte) []byte { + var out []byte + if len(domain) > MaxDstLen { + h.Reset() + _, _ = h.Write(OversizeDstSalt) + _, _ = h.Write(domain) + out = h.Sum(nil) + } else { + out = domain + } + return out +} + +func getDomainXof(h sha3.ShakeHash, domain []byte) []byte { + var out []byte + if len(domain) > MaxDstLen { + h.Reset() + _, _ = h.Write(OversizeDstSalt) + _, _ = h.Write(domain) + var tv [64]byte + _, _ = h.Read(tv[:]) + out = tv[:] + } else { + out = domain + } + return out +} + +// ExpandMsgXmd expands the msg with the domain to output a byte array +// with outLen in size using a fixed size hash. +// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.1 +func ExpandMsgXmd(h *EllipticPointHasher, msg, domain []byte, outLen int) []byte { + domain = getDomainXmd(h.xmd, domain) + domainLen := byte(len(domain)) + h.xmd.Reset() + // DST_prime = DST || I2OSP(len(DST), 1) + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + _, _ = h.xmd.Write(make([]byte, h.xmd.BlockSize())) + _, _ = h.xmd.Write(msg) + _, _ = h.xmd.Write([]byte{uint8(outLen >> 8), uint8(outLen)}) + _, _ = h.xmd.Write([]byte{0}) + _, _ = h.xmd.Write(domain) + _, _ = h.xmd.Write([]byte{domainLen}) + b0 := h.xmd.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.xmd.Reset() + _, _ = h.xmd.Write(b0) + _, _ = h.xmd.Write([]byte{1}) + _, _ = h.xmd.Write(domain) + _, _ = h.xmd.Write([]byte{domainLen}) + b1 := h.xmd.Sum(nil) + + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + ell := (outLen + h.xmd.Size() - 1) / h.xmd.Size() + bi := b1 + out := make([]byte, outLen) + for i := 1; i < ell; i++ { + h.xmd.Reset() + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + tmp := make([]byte, h.xmd.Size()) + for j := 0; j < h.xmd.Size(); j++ { + tmp[j] = b0[j] ^ bi[j] + } + _, _ = h.xmd.Write(tmp) + _, _ = h.xmd.Write([]byte{1 + uint8(i)}) + _, _ = h.xmd.Write(domain) + _, _ = h.xmd.Write([]byte{domainLen}) + + // b_1 || ... || b_(ell - 1) + copy(out[(i-1)*h.xmd.Size():i*h.xmd.Size()], bi[:]) + bi = h.xmd.Sum(nil) + } + // b_ell + copy(out[(ell-1)*h.xmd.Size():], bi[:]) + return out[:outLen] +} + +// ExpandMsgXof expands the msg with the domain to output a byte array +// with outLen in size using a xof hash +// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-13#section-5.4.2 +func ExpandMsgXof(h *EllipticPointHasher, msg, domain []byte, outLen int) []byte { + domain = getDomainXof(h.xof, domain) + domainLen := byte(len(domain)) + h.xof.Reset() + _, _ = h.xof.Write(msg) + _, _ = h.xof.Write([]byte{uint8(outLen >> 8), uint8(outLen)}) + _, _ = h.xof.Write(domain) + _, _ = h.xof.Write([]byte{domainLen}) + out := make([]byte, outLen) + _, _ = h.xof.Read(out) + return out +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/isogeny.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/isogeny.go new file mode 100644 index 0000000000..b4addb3dc0 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/isogeny.go @@ -0,0 +1,62 @@ +package native + +// IsogenyParams are the parameters needed to map from an isogeny to the main curve +type IsogenyParams struct { + XNum [][FieldLimbs]uint64 + XDen [][FieldLimbs]uint64 + YNum [][FieldLimbs]uint64 + YDen [][FieldLimbs]uint64 +} + +// Map from the isogeny curve to the main curve using the parameters +func (p *IsogenyParams) Map(xIn, yIn *Field) (x, y *Field) { + var xNum, xDen, yNum, yDen, tv [FieldLimbs]uint64 + var wasInverted int + + xnumL := len(p.XNum) + xdenL := len(p.XDen) + ynumL := len(p.YNum) + ydenL := len(p.YDen) + + degree := 0 + for _, i := range []int{xnumL, xdenL, ynumL, ydenL} { + if degree < i { + degree = i + } + } + + xs := make([][FieldLimbs]uint64, degree) + xs[0] = xIn.Params.R // x[0] = x^0 + xs[1] = xIn.Value // x[1] = x^1 + xIn.Arithmetic.Square(&xs[2], &xIn.Value) // x[2] = x^2 + for i := 3; i < degree; i++ { + // x[i] = x^i + xIn.Arithmetic.Mul(&xs[i], &xs[i-1], &xIn.Value) + } + + computeIsoK(&xNum, &xs, &p.XNum, xIn.Arithmetic) + computeIsoK(&xDen, &xs, &p.XDen, xIn.Arithmetic) + computeIsoK(&yNum, &xs, &p.YNum, xIn.Arithmetic) + computeIsoK(&yDen, &xs, &p.YDen, xIn.Arithmetic) + + xIn.Arithmetic.Invert(&wasInverted, &xDen, &xDen) + x = new(Field).Set(xIn) + xIn.Arithmetic.Mul(&tv, &xNum, &xDen) + xIn.Arithmetic.Selectznz(&x.Value, &x.Value, &tv, wasInverted) + + yIn.Arithmetic.Invert(&wasInverted, &yDen, &yDen) + y = new(Field).Set(yIn) + yIn.Arithmetic.Mul(&tv, &yNum, &yDen) + yIn.Arithmetic.Selectznz(&y.Value, &y.Value, &tv, wasInverted) + yIn.Arithmetic.Mul(&y.Value, &y.Value, &yIn.Value) + return +} + +func computeIsoK(out *[FieldLimbs]uint64, xxs, k *[][FieldLimbs]uint64, f FieldArithmetic) { + var tv [FieldLimbs]uint64 + + for i := range *k { + f.Mul(&tv, &(*xxs)[i], &(*k)[i]) + f.Add(out, out, &tv) + } +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/fp.go new file mode 100644 index 0000000000..ed1a72b0af --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/fp.go @@ -0,0 +1,173 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fp + +import ( + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var k256FpInitonce sync.Once +var k256FpParams native.FieldParams + +func K256FpNew() *native.Field { + return &native.Field{ + Value: [native.FieldLimbs]uint64{}, + Params: getK256FpParams(), + Arithmetic: k256FpArithmetic{}, + } +} + +func k256FpParamsInit() { + k256FpParams = native.FieldParams{ + R: [native.FieldLimbs]uint64{0x00000001000003d1, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, + R2: [native.FieldLimbs]uint64{0x000007a2000e90a1, 0x0000000000000001, 0x0000000000000000, 0x0000000000000000}, + R3: [native.FieldLimbs]uint64{0x002bb1e33795f671, 0x0000000100000b73, 0x0000000000000000, 0x0000000000000000}, + Modulus: [native.FieldLimbs]uint64{0xfffffffefffffc2f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}, + BiModulus: new(big.Int).SetBytes([]byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, + }), + } +} + +func getK256FpParams() *native.FieldParams { + k256FpInitonce.Do(k256FpParamsInit) + return &k256FpParams +} + +// k256FpArithmetic is a struct with all the methods needed for working +// in mod p +type k256FpArithmetic struct{} + +// ToMontgomery converts this field to montgomery form +func (f k256FpArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) { + ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg)) +} + +// FromMontgomery converts this field from montgomery form +func (f k256FpArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) { + FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Neg performs modular negation +func (f k256FpArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) { + Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Square performs modular square +func (f k256FpArithmetic) Square(out, arg *[native.FieldLimbs]uint64) { + Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Mul performs modular multiplication +func (f k256FpArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Add performs modular addition +func (f k256FpArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sub performs modular subtraction +func (f k256FpArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sqrt performs modular square root +func (f k256FpArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) { + // p is congruent to 3 mod 4 we can compute + // sqrt using elem^(p+1)/4 mod p + // 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c + var s, t [native.FieldLimbs]uint64 + params := getK256FpParams() + native.Pow(&s, arg, &[native.FieldLimbs]uint64{ + 0xffffffffbfffff0c, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x3fffffffffffffff, + }, params, f) + f.Square(&t, &s) + tv1 := &native.Field{Value: t, Params: params, Arithmetic: f} + tv2 := &native.Field{Value: *arg, Params: params, Arithmetic: f} + *wasSquare = tv1.Equal(tv2) + f.Selectznz(out, out, &s, *wasSquare) +} + +// Invert performs modular inverse +func (f k256FpArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) { + // The binary representation of (p - 2) has 5 groups of 1s, with lengths in + // { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each group: + // [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + var s, x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223 [native.FieldLimbs]uint64 + + native.Pow2k(&x2, arg, 1, f) + f.Mul(&x2, &x2, arg) + + native.Pow2k(&x3, &x2, 1, f) + f.Mul(&x3, &x3, arg) + + native.Pow2k(&x6, &x3, 3, f) + f.Mul(&x6, &x6, &x3) + + native.Pow2k(&x9, &x6, 3, f) + f.Mul(&x9, &x9, &x3) + + native.Pow2k(&x11, &x9, 2, f) + f.Mul(&x11, &x11, &x2) + + native.Pow2k(&x22, &x11, 11, f) + f.Mul(&x22, &x22, &x11) + + native.Pow2k(&x44, &x22, 22, f) + f.Mul(&x44, &x44, &x22) + + native.Pow2k(&x88, &x44, 44, f) + f.Mul(&x88, &x88, &x44) + + native.Pow2k(&x176, &x88, 88, f) + f.Mul(&x176, &x176, &x88) + + native.Pow2k(&x220, &x176, 44, f) + f.Mul(&x220, &x220, &x44) + + native.Pow2k(&x223, &x220, 3, f) + f.Mul(&x223, &x223, &x3) + + // Use sliding window over the group + native.Pow2k(&s, &x223, 23, f) + f.Mul(&s, &s, &x22) + native.Pow2k(&s, &s, 5, f) + f.Mul(&s, &s, arg) + native.Pow2k(&s, &s, 3, f) + f.Mul(&s, &s, &x2) + native.Pow2k(&s, &s, 2, f) + f.Mul(&s, &s, arg) + + tv := &native.Field{Value: *arg, Params: getK256FpParams(), Arithmetic: f} + + *wasInverted = tv.IsNonZero() + f.Selectznz(out, out, &s, *wasInverted) +} + +// FromBytes converts a little endian byte array into a field element +func (f k256FpArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) { + FromBytes(out, arg) +} + +// ToBytes converts a field element to a little endian byte array +func (f k256FpArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) { + ToBytes(out, arg) +} + +// Selectznz performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f k256FpArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) { + Selectznz(out, uint1(choice), arg1, arg2) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/secp256k1_fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/secp256k1_fp.go new file mode 100644 index 0000000000..b19f53eeba --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp/secp256k1_fp.go @@ -0,0 +1,1848 @@ +// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --internal-static --package-case flatcase --public-function-case UpperCamelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case camelCase --no-prefix-fiat --doc-newline-in-typedef-bounds --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-text-before-function-name '' --doc-text-before-type-name '' --package-name secp256k1 '' 64 '2^256 - 2^32 - 977' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp +// +// curve description (via package name): secp256k1 +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp +// +// m = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f (from "2^256 - 2^32 - 977") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 +package fp + +import "math/bits" + +type uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// MontgomeryDomainFieldElement is a field element in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type MontgomeryDomainFieldElement [4]uint64 + +// NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type NonMontgomeryDomainFieldElement [4]uint64 + +// cmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func cmovznzU64(out1 *uint64, arg1 uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// Mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Mul(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xd838091dd2253531) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffffffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xffffffffffffffff) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xfffffffefffffc2f) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg2[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg2[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg2[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xd838091dd2253531) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffffffffffff) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xffffffffffffffff) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xfffffffefffffc2f) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg2[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg2[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg2[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg2[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xd838091dd2253531) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffffffffffff) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xffffffffffffffff) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xfffffffefffffc2f) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg2[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg2[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg2[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg2[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xd838091dd2253531) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffffffffffff) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xffffffffffffffff) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xfffffffefffffc2f) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xfffffffefffffc2f, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xffffffffffffffff, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffffffffffff, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func Square(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xd838091dd2253531) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffffffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xffffffffffffffff) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xfffffffefffffc2f) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg1[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg1[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg1[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xd838091dd2253531) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffffffffffff) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xffffffffffffffff) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xfffffffefffffc2f) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg1[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg1[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg1[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg1[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xd838091dd2253531) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffffffffffff) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xffffffffffffffff) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xfffffffefffffc2f) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg1[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg1[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg1[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg1[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xd838091dd2253531) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffffffffffff) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xffffffffffffffff) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xfffffffefffffc2f) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xfffffffefffffc2f, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xffffffffffffffff, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffffffffffff, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Add(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + var x10 uint64 + x9, x10 = bits.Sub64(x1, 0xfffffffefffffc2f, uint64(0x0)) + var x11 uint64 + var x12 uint64 + x11, x12 = bits.Sub64(x3, 0xffffffffffffffff, uint64(uint1(x10))) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Sub64(x5, 0xffffffffffffffff, uint64(uint1(x12))) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Sub64(x7, 0xffffffffffffffff, uint64(uint1(x14))) + var x18 uint64 + _, x18 = bits.Sub64(uint64(uint1(x8)), uint64(0x0), uint64(uint1(x16))) + var x19 uint64 + cmovznzU64(&x19, uint1(x18), x9, x1) + var x20 uint64 + cmovznzU64(&x20, uint1(x18), x11, x3) + var x21 uint64 + cmovznzU64(&x21, uint1(x18), x13, x5) + var x22 uint64 + cmovznzU64(&x22, uint1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// Sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Sub(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xfffffffefffffc2f), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, x9, uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, x9, uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, x9, uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// Opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func Opp(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xfffffffefffffc2f), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, x9, uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, x9, uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, x9, uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// FromMontgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func FromMontgomery(out1 *NonMontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0xd838091dd2253531) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0xffffffffffffffff) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0xffffffffffffffff) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x11, x10 = bits.Mul64(x2, 0xfffffffefffffc2f) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x11, x8, uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x9, x6, uint64(uint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(x7, x4, uint64(uint1(x15))) + var x19 uint64 + _, x19 = bits.Add64(x1, x10, uint64(0x0)) + var x20 uint64 + var x21 uint64 + x20, x21 = bits.Add64(uint64(0x0), x12, uint64(uint1(x19))) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(uint64(0x0), x14, uint64(uint1(x21))) + var x24 uint64 + var x25 uint64 + x24, x25 = bits.Add64(uint64(0x0), x16, uint64(uint1(x23))) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(uint64(0x0), (uint64(uint1(x17)) + x5), uint64(uint1(x25))) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x20, arg1[1], uint64(0x0)) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x22, uint64(0x0), uint64(uint1(x29))) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x24, uint64(0x0), uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x26, uint64(0x0), uint64(uint1(x33))) + var x36 uint64 + _, x36 = bits.Mul64(x28, 0xd838091dd2253531) + var x38 uint64 + var x39 uint64 + x39, x38 = bits.Mul64(x36, 0xffffffffffffffff) + var x40 uint64 + var x41 uint64 + x41, x40 = bits.Mul64(x36, 0xffffffffffffffff) + var x42 uint64 + var x43 uint64 + x43, x42 = bits.Mul64(x36, 0xffffffffffffffff) + var x44 uint64 + var x45 uint64 + x45, x44 = bits.Mul64(x36, 0xfffffffefffffc2f) + var x46 uint64 + var x47 uint64 + x46, x47 = bits.Add64(x45, x42, uint64(0x0)) + var x48 uint64 + var x49 uint64 + x48, x49 = bits.Add64(x43, x40, uint64(uint1(x47))) + var x50 uint64 + var x51 uint64 + x50, x51 = bits.Add64(x41, x38, uint64(uint1(x49))) + var x53 uint64 + _, x53 = bits.Add64(x28, x44, uint64(0x0)) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64(x30, x46, uint64(uint1(x53))) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x32, x48, uint64(uint1(x55))) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x34, x50, uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64((uint64(uint1(x35)) + uint64(uint1(x27))), (uint64(uint1(x51)) + x39), uint64(uint1(x59))) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x54, arg1[2], uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x56, uint64(0x0), uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x58, uint64(0x0), uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x60, uint64(0x0), uint64(uint1(x67))) + var x70 uint64 + _, x70 = bits.Mul64(x62, 0xd838091dd2253531) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x70, 0xffffffffffffffff) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x70, 0xffffffffffffffff) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x70, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x70, 0xfffffffefffffc2f) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x79, x76, uint64(0x0)) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x77, x74, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x75, x72, uint64(uint1(x83))) + var x87 uint64 + _, x87 = bits.Add64(x62, x78, uint64(0x0)) + var x88 uint64 + var x89 uint64 + x88, x89 = bits.Add64(x64, x80, uint64(uint1(x87))) + var x90 uint64 + var x91 uint64 + x90, x91 = bits.Add64(x66, x82, uint64(uint1(x89))) + var x92 uint64 + var x93 uint64 + x92, x93 = bits.Add64(x68, x84, uint64(uint1(x91))) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64((uint64(uint1(x69)) + uint64(uint1(x61))), (uint64(uint1(x85)) + x73), uint64(uint1(x93))) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x88, arg1[3], uint64(0x0)) + var x98 uint64 + var x99 uint64 + x98, x99 = bits.Add64(x90, uint64(0x0), uint64(uint1(x97))) + var x100 uint64 + var x101 uint64 + x100, x101 = bits.Add64(x92, uint64(0x0), uint64(uint1(x99))) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Add64(x94, uint64(0x0), uint64(uint1(x101))) + var x104 uint64 + _, x104 = bits.Mul64(x96, 0xd838091dd2253531) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x104, 0xffffffffffffffff) + var x108 uint64 + var x109 uint64 + x109, x108 = bits.Mul64(x104, 0xffffffffffffffff) + var x110 uint64 + var x111 uint64 + x111, x110 = bits.Mul64(x104, 0xffffffffffffffff) + var x112 uint64 + var x113 uint64 + x113, x112 = bits.Mul64(x104, 0xfffffffefffffc2f) + var x114 uint64 + var x115 uint64 + x114, x115 = bits.Add64(x113, x110, uint64(0x0)) + var x116 uint64 + var x117 uint64 + x116, x117 = bits.Add64(x111, x108, uint64(uint1(x115))) + var x118 uint64 + var x119 uint64 + x118, x119 = bits.Add64(x109, x106, uint64(uint1(x117))) + var x121 uint64 + _, x121 = bits.Add64(x96, x112, uint64(0x0)) + var x122 uint64 + var x123 uint64 + x122, x123 = bits.Add64(x98, x114, uint64(uint1(x121))) + var x124 uint64 + var x125 uint64 + x124, x125 = bits.Add64(x100, x116, uint64(uint1(x123))) + var x126 uint64 + var x127 uint64 + x126, x127 = bits.Add64(x102, x118, uint64(uint1(x125))) + var x128 uint64 + var x129 uint64 + x128, x129 = bits.Add64((uint64(uint1(x103)) + uint64(uint1(x95))), (uint64(uint1(x119)) + x107), uint64(uint1(x127))) + var x130 uint64 + var x131 uint64 + x130, x131 = bits.Sub64(x122, 0xfffffffefffffc2f, uint64(0x0)) + var x132 uint64 + var x133 uint64 + x132, x133 = bits.Sub64(x124, 0xffffffffffffffff, uint64(uint1(x131))) + var x134 uint64 + var x135 uint64 + x134, x135 = bits.Sub64(x126, 0xffffffffffffffff, uint64(uint1(x133))) + var x136 uint64 + var x137 uint64 + x136, x137 = bits.Sub64(x128, 0xffffffffffffffff, uint64(uint1(x135))) + var x139 uint64 + _, x139 = bits.Sub64(uint64(uint1(x129)), uint64(0x0), uint64(uint1(x137))) + var x140 uint64 + cmovznzU64(&x140, uint1(x139), x130, x122) + var x141 uint64 + cmovznzU64(&x141, uint1(x139), x132, x124) + var x142 uint64 + cmovznzU64(&x142, uint1(x139), x134, x126) + var x143 uint64 + cmovznzU64(&x143, uint1(x139), x136, x128) + out1[0] = x140 + out1[1] = x141 + out1[2] = x142 + out1[3] = x143 +} + +// ToMontgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func ToMontgomery(out1 *MontgomeryDomainFieldElement, arg1 *NonMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x7a2000e90a1) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Add64(x6, x4, uint64(0x0)) + var x9 uint64 + _, x9 = bits.Mul64(x5, 0xd838091dd2253531) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x9, 0xffffffffffffffff) + var x13 uint64 + var x14 uint64 + x14, x13 = bits.Mul64(x9, 0xffffffffffffffff) + var x15 uint64 + var x16 uint64 + x16, x15 = bits.Mul64(x9, 0xffffffffffffffff) + var x17 uint64 + var x18 uint64 + x18, x17 = bits.Mul64(x9, 0xfffffffefffffc2f) + var x19 uint64 + var x20 uint64 + x19, x20 = bits.Add64(x18, x15, uint64(0x0)) + var x21 uint64 + var x22 uint64 + x21, x22 = bits.Add64(x16, x13, uint64(uint1(x20))) + var x23 uint64 + var x24 uint64 + x23, x24 = bits.Add64(x14, x11, uint64(uint1(x22))) + var x26 uint64 + _, x26 = bits.Add64(x5, x17, uint64(0x0)) + var x27 uint64 + var x28 uint64 + x27, x28 = bits.Add64(x7, x19, uint64(uint1(x26))) + var x29 uint64 + var x30 uint64 + x29, x30 = bits.Add64(uint64(uint1(x8)), x21, uint64(uint1(x28))) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(uint64(0x0), x23, uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(uint64(0x0), (uint64(uint1(x24)) + x12), uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x36, x35 = bits.Mul64(x1, 0x7a2000e90a1) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x36, x1, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x27, x35, uint64(0x0)) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x29, x37, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x31, uint64(uint1(x38)), uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x33, uint64(0x0), uint64(uint1(x44))) + var x47 uint64 + _, x47 = bits.Mul64(x39, 0xd838091dd2253531) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x47, 0xffffffffffffffff) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x47, 0xffffffffffffffff) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x47, 0xffffffffffffffff) + var x55 uint64 + var x56 uint64 + x56, x55 = bits.Mul64(x47, 0xfffffffefffffc2f) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x56, x53, uint64(0x0)) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x54, x51, uint64(uint1(x58))) + var x61 uint64 + var x62 uint64 + x61, x62 = bits.Add64(x52, x49, uint64(uint1(x60))) + var x64 uint64 + _, x64 = bits.Add64(x39, x55, uint64(0x0)) + var x65 uint64 + var x66 uint64 + x65, x66 = bits.Add64(x41, x57, uint64(uint1(x64))) + var x67 uint64 + var x68 uint64 + x67, x68 = bits.Add64(x43, x59, uint64(uint1(x66))) + var x69 uint64 + var x70 uint64 + x69, x70 = bits.Add64(x45, x61, uint64(uint1(x68))) + var x71 uint64 + var x72 uint64 + x71, x72 = bits.Add64((uint64(uint1(x46)) + uint64(uint1(x34))), (uint64(uint1(x62)) + x50), uint64(uint1(x70))) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(x2, 0x7a2000e90a1) + var x75 uint64 + var x76 uint64 + x75, x76 = bits.Add64(x74, x2, uint64(0x0)) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x65, x73, uint64(0x0)) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x67, x75, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x69, uint64(uint1(x76)), uint64(uint1(x80))) + var x83 uint64 + var x84 uint64 + x83, x84 = bits.Add64(x71, uint64(0x0), uint64(uint1(x82))) + var x85 uint64 + _, x85 = bits.Mul64(x77, 0xd838091dd2253531) + var x87 uint64 + var x88 uint64 + x88, x87 = bits.Mul64(x85, 0xffffffffffffffff) + var x89 uint64 + var x90 uint64 + x90, x89 = bits.Mul64(x85, 0xffffffffffffffff) + var x91 uint64 + var x92 uint64 + x92, x91 = bits.Mul64(x85, 0xffffffffffffffff) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(x85, 0xfffffffefffffc2f) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x94, x91, uint64(0x0)) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x92, x89, uint64(uint1(x96))) + var x99 uint64 + var x100 uint64 + x99, x100 = bits.Add64(x90, x87, uint64(uint1(x98))) + var x102 uint64 + _, x102 = bits.Add64(x77, x93, uint64(0x0)) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x79, x95, uint64(uint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x81, x97, uint64(uint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x83, x99, uint64(uint1(x106))) + var x109 uint64 + var x110 uint64 + x109, x110 = bits.Add64((uint64(uint1(x84)) + uint64(uint1(x72))), (uint64(uint1(x100)) + x88), uint64(uint1(x108))) + var x111 uint64 + var x112 uint64 + x112, x111 = bits.Mul64(x3, 0x7a2000e90a1) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x112, x3, uint64(0x0)) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x103, x111, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x105, x113, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x107, uint64(uint1(x114)), uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x109, uint64(0x0), uint64(uint1(x120))) + var x123 uint64 + _, x123 = bits.Mul64(x115, 0xd838091dd2253531) + var x125 uint64 + var x126 uint64 + x126, x125 = bits.Mul64(x123, 0xffffffffffffffff) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x123, 0xffffffffffffffff) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x123, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x123, 0xfffffffefffffc2f) + var x133 uint64 + var x134 uint64 + x133, x134 = bits.Add64(x132, x129, uint64(0x0)) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x130, x127, uint64(uint1(x134))) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x128, x125, uint64(uint1(x136))) + var x140 uint64 + _, x140 = bits.Add64(x115, x131, uint64(0x0)) + var x141 uint64 + var x142 uint64 + x141, x142 = bits.Add64(x117, x133, uint64(uint1(x140))) + var x143 uint64 + var x144 uint64 + x143, x144 = bits.Add64(x119, x135, uint64(uint1(x142))) + var x145 uint64 + var x146 uint64 + x145, x146 = bits.Add64(x121, x137, uint64(uint1(x144))) + var x147 uint64 + var x148 uint64 + x147, x148 = bits.Add64((uint64(uint1(x122)) + uint64(uint1(x110))), (uint64(uint1(x138)) + x126), uint64(uint1(x146))) + var x149 uint64 + var x150 uint64 + x149, x150 = bits.Sub64(x141, 0xfffffffefffffc2f, uint64(0x0)) + var x151 uint64 + var x152 uint64 + x151, x152 = bits.Sub64(x143, 0xffffffffffffffff, uint64(uint1(x150))) + var x153 uint64 + var x154 uint64 + x153, x154 = bits.Sub64(x145, 0xffffffffffffffff, uint64(uint1(x152))) + var x155 uint64 + var x156 uint64 + x155, x156 = bits.Sub64(x147, 0xffffffffffffffff, uint64(uint1(x154))) + var x158 uint64 + _, x158 = bits.Sub64(uint64(uint1(x148)), uint64(0x0), uint64(uint1(x156))) + var x159 uint64 + cmovznzU64(&x159, uint1(x158), x149, x141) + var x160 uint64 + cmovznzU64(&x160, uint1(x158), x151, x143) + var x161 uint64 + cmovznzU64(&x161, uint1(x158), x153, x145) + var x162 uint64 + cmovznzU64(&x162, uint1(x158), x155, x147) + out1[0] = x159 + out1[1] = x160 + out1[2] = x161 + out1[3] = x162 +} + +// Nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func Nonzero(out1 *uint64, arg1 *[4]uint64) { + x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) + *out1 = x1 +} + +// Selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Selectznz(out1 *[4]uint64, arg1 uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + cmovznzU64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + cmovznzU64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + cmovznzU64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + cmovznzU64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +func ToBytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func FromBytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} + +// SetOne returns the field element one in the Montgomery domain. +// +// Postconditions: +// eval (from_montgomery out1) mod m = 1 mod m +// 0 ≤ eval out1 < m +// +func SetOne(out1 *MontgomeryDomainFieldElement) { + out1[0] = 0x1000003d1 + out1[1] = uint64(0x0) + out1[2] = uint64(0x0) + out1[3] = uint64(0x0) +} + +// Msat returns the saturated representation of the prime modulus. +// +// Postconditions: +// twos_complement_eval out1 = m +// 0 ≤ eval out1 < m +// +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Msat(out1 *[5]uint64) { + out1[0] = 0xfffffffefffffc2f + out1[1] = 0xffffffffffffffff + out1[2] = 0xffffffffffffffff + out1[3] = 0xffffffffffffffff + out1[4] = uint64(0x0) +} + +// Divstep computes a divstep. +// +// Preconditions: +// 0 ≤ eval arg4 < m +// 0 ≤ eval arg5 < m +// Postconditions: +// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1) +// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2) +// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋) +// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m) +// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m) +// 0 ≤ eval out5 < m +// 0 ≤ eval out5 < m +// 0 ≤ eval out2 < m +// 0 ≤ eval out3 < m +// +// Input Bounds: +// arg1: [0x0 ~> 0xffffffffffffffff] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Divstep(out1 *uint64, out2 *[5]uint64, out3 *[5]uint64, out4 *[4]uint64, out5 *[4]uint64, arg1 uint64, arg2 *[5]uint64, arg3 *[5]uint64, arg4 *[4]uint64, arg5 *[4]uint64) { + var x1 uint64 + x1, _ = bits.Add64((^arg1), uint64(0x1), uint64(0x0)) + x3 := (uint1((x1 >> 63)) & (uint1(arg3[0]) & 0x1)) + var x4 uint64 + x4, _ = bits.Add64((^arg1), uint64(0x1), uint64(0x0)) + var x6 uint64 + cmovznzU64(&x6, x3, arg1, x4) + var x7 uint64 + cmovznzU64(&x7, x3, arg2[0], arg3[0]) + var x8 uint64 + cmovznzU64(&x8, x3, arg2[1], arg3[1]) + var x9 uint64 + cmovznzU64(&x9, x3, arg2[2], arg3[2]) + var x10 uint64 + cmovznzU64(&x10, x3, arg2[3], arg3[3]) + var x11 uint64 + cmovznzU64(&x11, x3, arg2[4], arg3[4]) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(uint64(0x1), (^arg2[0]), uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(uint64(0x0), (^arg2[1]), uint64(uint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(uint64(0x0), (^arg2[2]), uint64(uint1(x15))) + var x18 uint64 + var x19 uint64 + x18, x19 = bits.Add64(uint64(0x0), (^arg2[3]), uint64(uint1(x17))) + var x20 uint64 + x20, _ = bits.Add64(uint64(0x0), (^arg2[4]), uint64(uint1(x19))) + var x22 uint64 + cmovznzU64(&x22, x3, arg3[0], x12) + var x23 uint64 + cmovznzU64(&x23, x3, arg3[1], x14) + var x24 uint64 + cmovznzU64(&x24, x3, arg3[2], x16) + var x25 uint64 + cmovznzU64(&x25, x3, arg3[3], x18) + var x26 uint64 + cmovznzU64(&x26, x3, arg3[4], x20) + var x27 uint64 + cmovznzU64(&x27, x3, arg4[0], arg5[0]) + var x28 uint64 + cmovznzU64(&x28, x3, arg4[1], arg5[1]) + var x29 uint64 + cmovznzU64(&x29, x3, arg4[2], arg5[2]) + var x30 uint64 + cmovznzU64(&x30, x3, arg4[3], arg5[3]) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x27, x27, uint64(0x0)) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x28, x28, uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64(x29, x29, uint64(uint1(x34))) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x30, x30, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Sub64(x31, 0xfffffffefffffc2f, uint64(0x0)) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Sub64(x33, 0xffffffffffffffff, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Sub64(x35, 0xffffffffffffffff, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Sub64(x37, 0xffffffffffffffff, uint64(uint1(x44))) + var x48 uint64 + _, x48 = bits.Sub64(uint64(uint1(x38)), uint64(0x0), uint64(uint1(x46))) + x49 := arg4[3] + x50 := arg4[2] + x51 := arg4[1] + x52 := arg4[0] + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Sub64(uint64(0x0), x52, uint64(0x0)) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Sub64(uint64(0x0), x51, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Sub64(uint64(0x0), x50, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Sub64(uint64(0x0), x49, uint64(uint1(x58))) + var x61 uint64 + cmovznzU64(&x61, uint1(x60), uint64(0x0), 0xffffffffffffffff) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x53, (x61 & 0xfffffffefffffc2f), uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x55, x61, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x57, x61, uint64(uint1(x65))) + var x68 uint64 + x68, _ = bits.Add64(x59, x61, uint64(uint1(x67))) + var x70 uint64 + cmovznzU64(&x70, x3, arg5[0], x62) + var x71 uint64 + cmovznzU64(&x71, x3, arg5[1], x64) + var x72 uint64 + cmovznzU64(&x72, x3, arg5[2], x66) + var x73 uint64 + cmovznzU64(&x73, x3, arg5[3], x68) + x74 := (uint1(x22) & 0x1) + var x75 uint64 + cmovznzU64(&x75, x74, uint64(0x0), x7) + var x76 uint64 + cmovznzU64(&x76, x74, uint64(0x0), x8) + var x77 uint64 + cmovznzU64(&x77, x74, uint64(0x0), x9) + var x78 uint64 + cmovznzU64(&x78, x74, uint64(0x0), x10) + var x79 uint64 + cmovznzU64(&x79, x74, uint64(0x0), x11) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x22, x75, uint64(0x0)) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x23, x76, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x24, x77, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x25, x78, uint64(uint1(x85))) + var x88 uint64 + x88, _ = bits.Add64(x26, x79, uint64(uint1(x87))) + var x90 uint64 + cmovznzU64(&x90, x74, uint64(0x0), x27) + var x91 uint64 + cmovznzU64(&x91, x74, uint64(0x0), x28) + var x92 uint64 + cmovznzU64(&x92, x74, uint64(0x0), x29) + var x93 uint64 + cmovznzU64(&x93, x74, uint64(0x0), x30) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64(x70, x90, uint64(0x0)) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x71, x91, uint64(uint1(x95))) + var x98 uint64 + var x99 uint64 + x98, x99 = bits.Add64(x72, x92, uint64(uint1(x97))) + var x100 uint64 + var x101 uint64 + x100, x101 = bits.Add64(x73, x93, uint64(uint1(x99))) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Sub64(x94, 0xfffffffefffffc2f, uint64(0x0)) + var x104 uint64 + var x105 uint64 + x104, x105 = bits.Sub64(x96, 0xffffffffffffffff, uint64(uint1(x103))) + var x106 uint64 + var x107 uint64 + x106, x107 = bits.Sub64(x98, 0xffffffffffffffff, uint64(uint1(x105))) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Sub64(x100, 0xffffffffffffffff, uint64(uint1(x107))) + var x111 uint64 + _, x111 = bits.Sub64(uint64(uint1(x101)), uint64(0x0), uint64(uint1(x109))) + var x112 uint64 + x112, _ = bits.Add64(x6, uint64(0x1), uint64(0x0)) + x114 := ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff)) + x115 := ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff)) + x116 := ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff)) + x117 := ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff)) + x118 := ((x88 & 0x8000000000000000) | (x88 >> 1)) + var x119 uint64 + cmovznzU64(&x119, uint1(x48), x39, x31) + var x120 uint64 + cmovznzU64(&x120, uint1(x48), x41, x33) + var x121 uint64 + cmovznzU64(&x121, uint1(x48), x43, x35) + var x122 uint64 + cmovznzU64(&x122, uint1(x48), x45, x37) + var x123 uint64 + cmovznzU64(&x123, uint1(x111), x102, x94) + var x124 uint64 + cmovznzU64(&x124, uint1(x111), x104, x96) + var x125 uint64 + cmovznzU64(&x125, uint1(x111), x106, x98) + var x126 uint64 + cmovznzU64(&x126, uint1(x111), x108, x100) + *out1 = x112 + out2[0] = x7 + out2[1] = x8 + out2[2] = x9 + out2[3] = x10 + out2[4] = x11 + out3[0] = x114 + out3[1] = x115 + out3[2] = x116 + out3[3] = x117 + out3[4] = x118 + out4[0] = x119 + out4[1] = x120 + out4[2] = x121 + out4[3] = x122 + out5[0] = x123 + out5[1] = x124 + out5[2] = x125 + out5[3] = x126 +} + +// DivstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form). +// +// Postconditions: +// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if ⌊log2 m⌋ + 1 < 46 then ⌊(49 * (⌊log2 m⌋ + 1) + 80) / 17⌋ else ⌊(49 * (⌊log2 m⌋ + 1) + 57) / 17⌋) +// 0 ≤ eval out1 < m +// +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func DivstepPrecomp(out1 *[4]uint64) { + out1[0] = 0xf201a41831525e0a + out1[1] = 0x9953f9ddcd648d85 + out1[2] = 0xe86029463db210a9 + out1[3] = 0x24fb8a3104b03709 +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/fq.go new file mode 100644 index 0000000000..4965a80ef3 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/fq.go @@ -0,0 +1,284 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fq + +import ( + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var k256FqInitonce sync.Once +var k256FqParams native.FieldParams + +func K256FqNew() *native.Field { + return &native.Field{ + Value: [native.FieldLimbs]uint64{}, + Params: getK256FqParams(), + Arithmetic: k256FqArithmetic{}, + } +} + +func k256FqParamsInit() { + k256FqParams = native.FieldParams{ + R: [native.FieldLimbs]uint64{0x402da1732fc9bebf, 0x4551231950b75fc4, 0x0000000000000001, 0x0000000000000000}, + R2: [native.FieldLimbs]uint64{0x896cf21467d7d140, 0x741496c20e7cf878, 0xe697f5e45bcd07c6, 0x9d671cd581c69bc5}, + R3: [native.FieldLimbs]uint64{0x7bc0cfe0e9ff41ed, 0x0017648444d4322c, 0xb1b31347f1d0b2da, 0x555d800c18ef116d}, + Modulus: [native.FieldLimbs]uint64{0xbfd25e8cd0364141, 0xbaaedce6af48a03b, 0xfffffffffffffffe, 0xffffffffffffffff}, + BiModulus: new(big.Int).SetBytes([]byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41}, + ), + } +} + +func getK256FqParams() *native.FieldParams { + k256FqInitonce.Do(k256FqParamsInit) + return &k256FqParams +} + +// k256FqArithmetic is a struct with all the methods needed for working +// in mod q +type k256FqArithmetic struct{} + +// ToMontgomery converts this field to montgomery form +func (f k256FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) { + ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg)) +} + +// FromMontgomery converts this field from montgomery form +func (f k256FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) { + FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Neg performs modular negation +func (f k256FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) { + Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Square performs modular square +func (f k256FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) { + Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Mul performs modular multiplication +func (f k256FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Add performs modular addition +func (f k256FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sub performs modular subtraction +func (f k256FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sqrt performs modular square root +func (f k256FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) { + // See sqrt_ts_ct at + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4 + // c1 := 6 + // c2 := (q - 1) / (2^c1) + // c2 := [4]uint64{ + // 0xeeff497a3340d905, + // 0xfaeabb739abd2280, + // 0xffffffffffffffff, + // 0x03ffffffffffffff, + //} + // c3 := (c2 - 1) / 2 + c3 := [native.FieldLimbs]uint64{ + 0x777fa4bd19a06c82, + 0xfd755db9cd5e9140, + 0xffffffffffffffff, + 0x01ffffffffffffff, + } + //c4 := generator + //c5 := new(Fq).pow(generator, c2) + c5 := [native.FieldLimbs]uint64{0x944cf2a220910e04, 0x815c829c780589f4, 0x55980b07bc222113, 0xc702b0d248825b36} + var z, t, b, c, tv [native.FieldLimbs]uint64 + + native.Pow(&z, arg, &c3, getK256FqParams(), f) + Square((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&z)) + Mul((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(arg)) + Mul((*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(arg)) + + copy(b[:], t[:]) + copy(c[:], c5[:]) + + for i := s; i >= 2; i-- { + for j := 1; j <= i-2; j++ { + Square((*MontgomeryDomainFieldElement)(&b), (*MontgomeryDomainFieldElement)(&b)) + } + // if b == 1 flag = 0 else flag = 1 + flag := -(&native.Field{ + Value: b, + Params: getK256FqParams(), + Arithmetic: f, + }).IsOne() + 1 + Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&c)) + Selectznz(&z, uint1(flag), &z, &tv) + Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&c)) + Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&c)) + Selectznz(&t, uint1(flag), &t, &tv) + copy(b[:], t[:]) + } + Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&z)) + *wasSquare = (&native.Field{ + Value: c, + Params: getK256FqParams(), + Arithmetic: f, + }).Equal(&native.Field{ + Value: *arg, + Params: getK256FqParams(), + Arithmetic: f, + }) + Selectznz(out, uint1(*wasSquare), out, &z) +} + +// Invert performs modular inverse +func (f k256FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) { + // Using an addition chain from + // https://briansmith.org/ecc-inversion-addition-chains-01#secp256k1_scalar_inversion + var x1, x10, x11, x101, x111, x1001, x1011, x1101 [native.FieldLimbs]uint64 + var x6, x8, x14, x28, x56, tmp [native.FieldLimbs]uint64 + + copy(x1[:], arg[:]) + native.Pow2k(&x10, arg, 1, f) + Mul((*MontgomeryDomainFieldElement)(&x11), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1)) + Mul((*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x11)) + Mul((*MontgomeryDomainFieldElement)(&x111), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x101)) + Mul((*MontgomeryDomainFieldElement)(&x1001), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x111)) + Mul((*MontgomeryDomainFieldElement)(&x1011), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1001)) + Mul((*MontgomeryDomainFieldElement)(&x1101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1011)) + + native.Pow2k(&x6, &x1101, 2, f) + Mul((*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x1011)) + + native.Pow2k(&x8, &x6, 2, f) + Mul((*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&x14, &x8, 6, f) + Mul((*MontgomeryDomainFieldElement)(&x14), (*MontgomeryDomainFieldElement)(&x14), (*MontgomeryDomainFieldElement)(&x6)) + + native.Pow2k(&x28, &x14, 14, f) + Mul((*MontgomeryDomainFieldElement)(&x28), (*MontgomeryDomainFieldElement)(&x28), (*MontgomeryDomainFieldElement)(&x14)) + + native.Pow2k(&x56, &x28, 28, f) + Mul((*MontgomeryDomainFieldElement)(&x56), (*MontgomeryDomainFieldElement)(&x56), (*MontgomeryDomainFieldElement)(&x28)) + + native.Pow2k(&tmp, &x56, 56, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x56)) + + native.Pow2k(&tmp, &tmp, 14, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x14)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 10, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 9, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x8)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1011)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101)) + + native.Pow2k(&tmp, &tmp, 10, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1101)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1001)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1)) + + native.Pow2k(&tmp, &tmp, 8, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x6)) + + *wasInverted = (&native.Field{ + Value: *arg, + Params: getK256FqParams(), + Arithmetic: f, + }).IsNonZero() + Selectznz(out, uint1(*wasInverted), out, &tmp) +} + +// FromBytes converts a little endian byte array into a field element +func (f k256FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) { + FromBytes(out, arg) +} + +// ToBytes converts a field element to a little endian byte array +func (f k256FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) { + ToBytes(out, arg) +} + +// Selectznz performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f k256FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) { + Selectznz(out, uint1(choice), arg1, arg2) +} + +// generator = 7 mod q is a generator of the `q - 1` order multiplicative +// subgroup, or in other words a primitive element of the field. +// generator^t where t * 2^s + 1 = q +var generator = &[native.FieldLimbs]uint64{0xc13f6a264e843739, 0xe537f5b135039e5d, 0x0000000000000008, 0x0000000000000000} + +// s satisfies the equation 2^s * t = q - 1 with t odd. +var s = 6 diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/secp256k1_fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/secp256k1_fq.go new file mode 100644 index 0000000000..3c0e584b81 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq/secp256k1_fq.go @@ -0,0 +1,1908 @@ +// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --internal-static --package-case flatcase --public-function-case UpperCamelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case camelCase --no-prefix-fiat --doc-newline-in-typedef-bounds --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-text-before-function-name '' --doc-text-before-type-name '' --package-name secp256k1_q '' 64 '2^256 - 432420386565659656852420866394968145599' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp +// +// curve description (via package name): secp256k1_q +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp +// +// m = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 (from "2^256 - 432420386565659656852420866394968145599") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 +package fq + +import "math/bits" + +type uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// MontgomeryDomainFieldElement is a field element in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type MontgomeryDomainFieldElement [4]uint64 + +// NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type NonMontgomeryDomainFieldElement [4]uint64 + +// cmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func cmovznzU64(out1 *uint64, arg1 uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// Mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Mul(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x4b0dff665588b13f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffffffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xfffffffffffffffe) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbaaedce6af48a03b) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xbfd25e8cd0364141) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg2[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg2[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg2[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0x4b0dff665588b13f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffffffffffff) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xfffffffffffffffe) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbaaedce6af48a03b) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xbfd25e8cd0364141) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg2[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg2[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg2[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg2[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0x4b0dff665588b13f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffffffffffff) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xfffffffffffffffe) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbaaedce6af48a03b) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xbfd25e8cd0364141) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg2[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg2[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg2[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg2[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0x4b0dff665588b13f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffffffffffff) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xfffffffffffffffe) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbaaedce6af48a03b) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xbfd25e8cd0364141) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xbfd25e8cd0364141, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbaaedce6af48a03b, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xfffffffffffffffe, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffffffffffff, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func Square(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x4b0dff665588b13f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffffffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xfffffffffffffffe) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbaaedce6af48a03b) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xbfd25e8cd0364141) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg1[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg1[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg1[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0x4b0dff665588b13f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffffffffffff) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xfffffffffffffffe) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbaaedce6af48a03b) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xbfd25e8cd0364141) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg1[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg1[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg1[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg1[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0x4b0dff665588b13f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffffffffffff) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xfffffffffffffffe) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbaaedce6af48a03b) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xbfd25e8cd0364141) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg1[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg1[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg1[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg1[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0x4b0dff665588b13f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffffffffffff) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xfffffffffffffffe) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbaaedce6af48a03b) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xbfd25e8cd0364141) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xbfd25e8cd0364141, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbaaedce6af48a03b, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xfffffffffffffffe, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffffffffffff, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Add(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + var x10 uint64 + x9, x10 = bits.Sub64(x1, 0xbfd25e8cd0364141, uint64(0x0)) + var x11 uint64 + var x12 uint64 + x11, x12 = bits.Sub64(x3, 0xbaaedce6af48a03b, uint64(uint1(x10))) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Sub64(x5, 0xfffffffffffffffe, uint64(uint1(x12))) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Sub64(x7, 0xffffffffffffffff, uint64(uint1(x14))) + var x18 uint64 + _, x18 = bits.Sub64(uint64(uint1(x8)), uint64(0x0), uint64(uint1(x16))) + var x19 uint64 + cmovznzU64(&x19, uint1(x18), x9, x1) + var x20 uint64 + cmovznzU64(&x20, uint1(x18), x11, x3) + var x21 uint64 + cmovznzU64(&x21, uint1(x18), x13, x5) + var x22 uint64 + cmovznzU64(&x22, uint1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// Sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Sub(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xbfd25e8cd0364141), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xbaaedce6af48a03b), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, (x9 & 0xfffffffffffffffe), uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, x9, uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// Opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func Opp(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xbfd25e8cd0364141), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xbaaedce6af48a03b), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, (x9 & 0xfffffffffffffffe), uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, x9, uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// FromMontgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func FromMontgomery(out1 *NonMontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0x4b0dff665588b13f) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0xffffffffffffffff) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0xfffffffffffffffe) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0xbaaedce6af48a03b) + var x10 uint64 + var x11 uint64 + x11, x10 = bits.Mul64(x2, 0xbfd25e8cd0364141) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x11, x8, uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x9, x6, uint64(uint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(x7, x4, uint64(uint1(x15))) + var x19 uint64 + _, x19 = bits.Add64(x1, x10, uint64(0x0)) + var x20 uint64 + var x21 uint64 + x20, x21 = bits.Add64(uint64(0x0), x12, uint64(uint1(x19))) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(uint64(0x0), x14, uint64(uint1(x21))) + var x24 uint64 + var x25 uint64 + x24, x25 = bits.Add64(uint64(0x0), x16, uint64(uint1(x23))) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(uint64(0x0), (uint64(uint1(x17)) + x5), uint64(uint1(x25))) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x20, arg1[1], uint64(0x0)) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x22, uint64(0x0), uint64(uint1(x29))) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x24, uint64(0x0), uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x26, uint64(0x0), uint64(uint1(x33))) + var x36 uint64 + _, x36 = bits.Mul64(x28, 0x4b0dff665588b13f) + var x38 uint64 + var x39 uint64 + x39, x38 = bits.Mul64(x36, 0xffffffffffffffff) + var x40 uint64 + var x41 uint64 + x41, x40 = bits.Mul64(x36, 0xfffffffffffffffe) + var x42 uint64 + var x43 uint64 + x43, x42 = bits.Mul64(x36, 0xbaaedce6af48a03b) + var x44 uint64 + var x45 uint64 + x45, x44 = bits.Mul64(x36, 0xbfd25e8cd0364141) + var x46 uint64 + var x47 uint64 + x46, x47 = bits.Add64(x45, x42, uint64(0x0)) + var x48 uint64 + var x49 uint64 + x48, x49 = bits.Add64(x43, x40, uint64(uint1(x47))) + var x50 uint64 + var x51 uint64 + x50, x51 = bits.Add64(x41, x38, uint64(uint1(x49))) + var x53 uint64 + _, x53 = bits.Add64(x28, x44, uint64(0x0)) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64(x30, x46, uint64(uint1(x53))) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x32, x48, uint64(uint1(x55))) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x34, x50, uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64((uint64(uint1(x35)) + uint64(uint1(x27))), (uint64(uint1(x51)) + x39), uint64(uint1(x59))) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x54, arg1[2], uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x56, uint64(0x0), uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x58, uint64(0x0), uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x60, uint64(0x0), uint64(uint1(x67))) + var x70 uint64 + _, x70 = bits.Mul64(x62, 0x4b0dff665588b13f) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x70, 0xffffffffffffffff) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x70, 0xfffffffffffffffe) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x70, 0xbaaedce6af48a03b) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x70, 0xbfd25e8cd0364141) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x79, x76, uint64(0x0)) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x77, x74, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x75, x72, uint64(uint1(x83))) + var x87 uint64 + _, x87 = bits.Add64(x62, x78, uint64(0x0)) + var x88 uint64 + var x89 uint64 + x88, x89 = bits.Add64(x64, x80, uint64(uint1(x87))) + var x90 uint64 + var x91 uint64 + x90, x91 = bits.Add64(x66, x82, uint64(uint1(x89))) + var x92 uint64 + var x93 uint64 + x92, x93 = bits.Add64(x68, x84, uint64(uint1(x91))) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64((uint64(uint1(x69)) + uint64(uint1(x61))), (uint64(uint1(x85)) + x73), uint64(uint1(x93))) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x88, arg1[3], uint64(0x0)) + var x98 uint64 + var x99 uint64 + x98, x99 = bits.Add64(x90, uint64(0x0), uint64(uint1(x97))) + var x100 uint64 + var x101 uint64 + x100, x101 = bits.Add64(x92, uint64(0x0), uint64(uint1(x99))) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Add64(x94, uint64(0x0), uint64(uint1(x101))) + var x104 uint64 + _, x104 = bits.Mul64(x96, 0x4b0dff665588b13f) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x104, 0xffffffffffffffff) + var x108 uint64 + var x109 uint64 + x109, x108 = bits.Mul64(x104, 0xfffffffffffffffe) + var x110 uint64 + var x111 uint64 + x111, x110 = bits.Mul64(x104, 0xbaaedce6af48a03b) + var x112 uint64 + var x113 uint64 + x113, x112 = bits.Mul64(x104, 0xbfd25e8cd0364141) + var x114 uint64 + var x115 uint64 + x114, x115 = bits.Add64(x113, x110, uint64(0x0)) + var x116 uint64 + var x117 uint64 + x116, x117 = bits.Add64(x111, x108, uint64(uint1(x115))) + var x118 uint64 + var x119 uint64 + x118, x119 = bits.Add64(x109, x106, uint64(uint1(x117))) + var x121 uint64 + _, x121 = bits.Add64(x96, x112, uint64(0x0)) + var x122 uint64 + var x123 uint64 + x122, x123 = bits.Add64(x98, x114, uint64(uint1(x121))) + var x124 uint64 + var x125 uint64 + x124, x125 = bits.Add64(x100, x116, uint64(uint1(x123))) + var x126 uint64 + var x127 uint64 + x126, x127 = bits.Add64(x102, x118, uint64(uint1(x125))) + var x128 uint64 + var x129 uint64 + x128, x129 = bits.Add64((uint64(uint1(x103)) + uint64(uint1(x95))), (uint64(uint1(x119)) + x107), uint64(uint1(x127))) + var x130 uint64 + var x131 uint64 + x130, x131 = bits.Sub64(x122, 0xbfd25e8cd0364141, uint64(0x0)) + var x132 uint64 + var x133 uint64 + x132, x133 = bits.Sub64(x124, 0xbaaedce6af48a03b, uint64(uint1(x131))) + var x134 uint64 + var x135 uint64 + x134, x135 = bits.Sub64(x126, 0xfffffffffffffffe, uint64(uint1(x133))) + var x136 uint64 + var x137 uint64 + x136, x137 = bits.Sub64(x128, 0xffffffffffffffff, uint64(uint1(x135))) + var x139 uint64 + _, x139 = bits.Sub64(uint64(uint1(x129)), uint64(0x0), uint64(uint1(x137))) + var x140 uint64 + cmovznzU64(&x140, uint1(x139), x130, x122) + var x141 uint64 + cmovznzU64(&x141, uint1(x139), x132, x124) + var x142 uint64 + cmovznzU64(&x142, uint1(x139), x134, x126) + var x143 uint64 + cmovznzU64(&x143, uint1(x139), x136, x128) + out1[0] = x140 + out1[1] = x141 + out1[2] = x142 + out1[3] = x143 +} + +// ToMontgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func ToMontgomery(out1 *MontgomeryDomainFieldElement, arg1 *NonMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x9d671cd581c69bc5) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0xe697f5e45bcd07c6) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0x741496c20e7cf878) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0x896cf21467d7d140) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + var x19 uint64 + _, x19 = bits.Mul64(x11, 0x4b0dff665588b13f) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x19, 0xffffffffffffffff) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x19, 0xfffffffffffffffe) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(x19, 0xbaaedce6af48a03b) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(x19, 0xbfd25e8cd0364141) + var x29 uint64 + var x30 uint64 + x29, x30 = bits.Add64(x28, x25, uint64(0x0)) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x26, x23, uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x24, x21, uint64(uint1(x32))) + var x36 uint64 + _, x36 = bits.Add64(x11, x27, uint64(0x0)) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x13, x29, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x15, x31, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x17, x33, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64((uint64(uint1(x18)) + x6), (uint64(uint1(x34)) + x22), uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, 0x9d671cd581c69bc5) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, 0xe697f5e45bcd07c6) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, 0x741496c20e7cf878) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, 0x896cf21467d7d140) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x52, x49, uint64(0x0)) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x50, x47, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x48, x45, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x37, x51, uint64(0x0)) + var x61 uint64 + var x62 uint64 + x61, x62 = bits.Add64(x39, x53, uint64(uint1(x60))) + var x63 uint64 + var x64 uint64 + x63, x64 = bits.Add64(x41, x55, uint64(uint1(x62))) + var x65 uint64 + var x66 uint64 + x65, x66 = bits.Add64(x43, x57, uint64(uint1(x64))) + var x67 uint64 + _, x67 = bits.Mul64(x59, 0x4b0dff665588b13f) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(x67, 0xffffffffffffffff) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(x67, 0xfffffffffffffffe) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(x67, 0xbaaedce6af48a03b) + var x75 uint64 + var x76 uint64 + x76, x75 = bits.Mul64(x67, 0xbfd25e8cd0364141) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x76, x73, uint64(0x0)) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x74, x71, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x72, x69, uint64(uint1(x80))) + var x84 uint64 + _, x84 = bits.Add64(x59, x75, uint64(0x0)) + var x85 uint64 + var x86 uint64 + x85, x86 = bits.Add64(x61, x77, uint64(uint1(x84))) + var x87 uint64 + var x88 uint64 + x87, x88 = bits.Add64(x63, x79, uint64(uint1(x86))) + var x89 uint64 + var x90 uint64 + x89, x90 = bits.Add64(x65, x81, uint64(uint1(x88))) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(((uint64(uint1(x66)) + uint64(uint1(x44))) + (uint64(uint1(x58)) + x46)), (uint64(uint1(x82)) + x70), uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(x2, 0x9d671cd581c69bc5) + var x95 uint64 + var x96 uint64 + x96, x95 = bits.Mul64(x2, 0xe697f5e45bcd07c6) + var x97 uint64 + var x98 uint64 + x98, x97 = bits.Mul64(x2, 0x741496c20e7cf878) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(x2, 0x896cf21467d7d140) + var x101 uint64 + var x102 uint64 + x101, x102 = bits.Add64(x100, x97, uint64(0x0)) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x98, x95, uint64(uint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x96, x93, uint64(uint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x85, x99, uint64(0x0)) + var x109 uint64 + var x110 uint64 + x109, x110 = bits.Add64(x87, x101, uint64(uint1(x108))) + var x111 uint64 + var x112 uint64 + x111, x112 = bits.Add64(x89, x103, uint64(uint1(x110))) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x91, x105, uint64(uint1(x112))) + var x115 uint64 + _, x115 = bits.Mul64(x107, 0x4b0dff665588b13f) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x115, 0xffffffffffffffff) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x115, 0xfffffffffffffffe) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x115, 0xbaaedce6af48a03b) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x115, 0xbfd25e8cd0364141) + var x125 uint64 + var x126 uint64 + x125, x126 = bits.Add64(x124, x121, uint64(0x0)) + var x127 uint64 + var x128 uint64 + x127, x128 = bits.Add64(x122, x119, uint64(uint1(x126))) + var x129 uint64 + var x130 uint64 + x129, x130 = bits.Add64(x120, x117, uint64(uint1(x128))) + var x132 uint64 + _, x132 = bits.Add64(x107, x123, uint64(0x0)) + var x133 uint64 + var x134 uint64 + x133, x134 = bits.Add64(x109, x125, uint64(uint1(x132))) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x111, x127, uint64(uint1(x134))) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x113, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(((uint64(uint1(x114)) + uint64(uint1(x92))) + (uint64(uint1(x106)) + x94)), (uint64(uint1(x130)) + x118), uint64(uint1(x138))) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, 0x9d671cd581c69bc5) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x3, 0xe697f5e45bcd07c6) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(x3, 0x741496c20e7cf878) + var x147 uint64 + var x148 uint64 + x148, x147 = bits.Mul64(x3, 0x896cf21467d7d140) + var x149 uint64 + var x150 uint64 + x149, x150 = bits.Add64(x148, x145, uint64(0x0)) + var x151 uint64 + var x152 uint64 + x151, x152 = bits.Add64(x146, x143, uint64(uint1(x150))) + var x153 uint64 + var x154 uint64 + x153, x154 = bits.Add64(x144, x141, uint64(uint1(x152))) + var x155 uint64 + var x156 uint64 + x155, x156 = bits.Add64(x133, x147, uint64(0x0)) + var x157 uint64 + var x158 uint64 + x157, x158 = bits.Add64(x135, x149, uint64(uint1(x156))) + var x159 uint64 + var x160 uint64 + x159, x160 = bits.Add64(x137, x151, uint64(uint1(x158))) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x139, x153, uint64(uint1(x160))) + var x163 uint64 + _, x163 = bits.Mul64(x155, 0x4b0dff665588b13f) + var x165 uint64 + var x166 uint64 + x166, x165 = bits.Mul64(x163, 0xffffffffffffffff) + var x167 uint64 + var x168 uint64 + x168, x167 = bits.Mul64(x163, 0xfffffffffffffffe) + var x169 uint64 + var x170 uint64 + x170, x169 = bits.Mul64(x163, 0xbaaedce6af48a03b) + var x171 uint64 + var x172 uint64 + x172, x171 = bits.Mul64(x163, 0xbfd25e8cd0364141) + var x173 uint64 + var x174 uint64 + x173, x174 = bits.Add64(x172, x169, uint64(0x0)) + var x175 uint64 + var x176 uint64 + x175, x176 = bits.Add64(x170, x167, uint64(uint1(x174))) + var x177 uint64 + var x178 uint64 + x177, x178 = bits.Add64(x168, x165, uint64(uint1(x176))) + var x180 uint64 + _, x180 = bits.Add64(x155, x171, uint64(0x0)) + var x181 uint64 + var x182 uint64 + x181, x182 = bits.Add64(x157, x173, uint64(uint1(x180))) + var x183 uint64 + var x184 uint64 + x183, x184 = bits.Add64(x159, x175, uint64(uint1(x182))) + var x185 uint64 + var x186 uint64 + x185, x186 = bits.Add64(x161, x177, uint64(uint1(x184))) + var x187 uint64 + var x188 uint64 + x187, x188 = bits.Add64(((uint64(uint1(x162)) + uint64(uint1(x140))) + (uint64(uint1(x154)) + x142)), (uint64(uint1(x178)) + x166), uint64(uint1(x186))) + var x189 uint64 + var x190 uint64 + x189, x190 = bits.Sub64(x181, 0xbfd25e8cd0364141, uint64(0x0)) + var x191 uint64 + var x192 uint64 + x191, x192 = bits.Sub64(x183, 0xbaaedce6af48a03b, uint64(uint1(x190))) + var x193 uint64 + var x194 uint64 + x193, x194 = bits.Sub64(x185, 0xfffffffffffffffe, uint64(uint1(x192))) + var x195 uint64 + var x196 uint64 + x195, x196 = bits.Sub64(x187, 0xffffffffffffffff, uint64(uint1(x194))) + var x198 uint64 + _, x198 = bits.Sub64(uint64(uint1(x188)), uint64(0x0), uint64(uint1(x196))) + var x199 uint64 + cmovznzU64(&x199, uint1(x198), x189, x181) + var x200 uint64 + cmovznzU64(&x200, uint1(x198), x191, x183) + var x201 uint64 + cmovznzU64(&x201, uint1(x198), x193, x185) + var x202 uint64 + cmovznzU64(&x202, uint1(x198), x195, x187) + out1[0] = x199 + out1[1] = x200 + out1[2] = x201 + out1[3] = x202 +} + +// Nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func Nonzero(out1 *uint64, arg1 *[4]uint64) { + x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) + *out1 = x1 +} + +// Selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Selectznz(out1 *[4]uint64, arg1 uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + cmovznzU64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + cmovznzU64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + cmovznzU64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + cmovznzU64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +func ToBytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func FromBytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} + +// SetOne returns the field element one in the Montgomery domain. +// +// Postconditions: +// eval (from_montgomery out1) mod m = 1 mod m +// 0 ≤ eval out1 < m +// +func SetOne(out1 *MontgomeryDomainFieldElement) { + out1[0] = 0x402da1732fc9bebf + out1[1] = 0x4551231950b75fc4 + out1[2] = uint64(0x1) + out1[3] = uint64(0x0) +} + +// Msat returns the saturated representation of the prime modulus. +// +// Postconditions: +// twos_complement_eval out1 = m +// 0 ≤ eval out1 < m +// +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Msat(out1 *[5]uint64) { + out1[0] = 0xbfd25e8cd0364141 + out1[1] = 0xbaaedce6af48a03b + out1[2] = 0xfffffffffffffffe + out1[3] = 0xffffffffffffffff + out1[4] = uint64(0x0) +} + +// Divstep computes a divstep. +// +// Preconditions: +// 0 ≤ eval arg4 < m +// 0 ≤ eval arg5 < m +// Postconditions: +// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1) +// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2) +// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋) +// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m) +// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m) +// 0 ≤ eval out5 < m +// 0 ≤ eval out5 < m +// 0 ≤ eval out2 < m +// 0 ≤ eval out3 < m +// +// Input Bounds: +// arg1: [0x0 ~> 0xffffffffffffffff] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Divstep(out1 *uint64, out2 *[5]uint64, out3 *[5]uint64, out4 *[4]uint64, out5 *[4]uint64, arg1 uint64, arg2 *[5]uint64, arg3 *[5]uint64, arg4 *[4]uint64, arg5 *[4]uint64) { + var x1 uint64 + x1, _ = bits.Add64((^arg1), uint64(0x1), uint64(0x0)) + x3 := (uint1((x1 >> 63)) & (uint1(arg3[0]) & 0x1)) + var x4 uint64 + x4, _ = bits.Add64((^arg1), uint64(0x1), uint64(0x0)) + var x6 uint64 + cmovznzU64(&x6, x3, arg1, x4) + var x7 uint64 + cmovznzU64(&x7, x3, arg2[0], arg3[0]) + var x8 uint64 + cmovznzU64(&x8, x3, arg2[1], arg3[1]) + var x9 uint64 + cmovznzU64(&x9, x3, arg2[2], arg3[2]) + var x10 uint64 + cmovznzU64(&x10, x3, arg2[3], arg3[3]) + var x11 uint64 + cmovznzU64(&x11, x3, arg2[4], arg3[4]) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(uint64(0x1), (^arg2[0]), uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(uint64(0x0), (^arg2[1]), uint64(uint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(uint64(0x0), (^arg2[2]), uint64(uint1(x15))) + var x18 uint64 + var x19 uint64 + x18, x19 = bits.Add64(uint64(0x0), (^arg2[3]), uint64(uint1(x17))) + var x20 uint64 + x20, _ = bits.Add64(uint64(0x0), (^arg2[4]), uint64(uint1(x19))) + var x22 uint64 + cmovznzU64(&x22, x3, arg3[0], x12) + var x23 uint64 + cmovznzU64(&x23, x3, arg3[1], x14) + var x24 uint64 + cmovznzU64(&x24, x3, arg3[2], x16) + var x25 uint64 + cmovznzU64(&x25, x3, arg3[3], x18) + var x26 uint64 + cmovznzU64(&x26, x3, arg3[4], x20) + var x27 uint64 + cmovznzU64(&x27, x3, arg4[0], arg5[0]) + var x28 uint64 + cmovznzU64(&x28, x3, arg4[1], arg5[1]) + var x29 uint64 + cmovznzU64(&x29, x3, arg4[2], arg5[2]) + var x30 uint64 + cmovznzU64(&x30, x3, arg4[3], arg5[3]) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x27, x27, uint64(0x0)) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x28, x28, uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64(x29, x29, uint64(uint1(x34))) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x30, x30, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Sub64(x31, 0xbfd25e8cd0364141, uint64(0x0)) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Sub64(x33, 0xbaaedce6af48a03b, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Sub64(x35, 0xfffffffffffffffe, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Sub64(x37, 0xffffffffffffffff, uint64(uint1(x44))) + var x48 uint64 + _, x48 = bits.Sub64(uint64(uint1(x38)), uint64(0x0), uint64(uint1(x46))) + x49 := arg4[3] + x50 := arg4[2] + x51 := arg4[1] + x52 := arg4[0] + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Sub64(uint64(0x0), x52, uint64(0x0)) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Sub64(uint64(0x0), x51, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Sub64(uint64(0x0), x50, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Sub64(uint64(0x0), x49, uint64(uint1(x58))) + var x61 uint64 + cmovznzU64(&x61, uint1(x60), uint64(0x0), 0xffffffffffffffff) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x53, (x61 & 0xbfd25e8cd0364141), uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x55, (x61 & 0xbaaedce6af48a03b), uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x57, (x61 & 0xfffffffffffffffe), uint64(uint1(x65))) + var x68 uint64 + x68, _ = bits.Add64(x59, x61, uint64(uint1(x67))) + var x70 uint64 + cmovznzU64(&x70, x3, arg5[0], x62) + var x71 uint64 + cmovznzU64(&x71, x3, arg5[1], x64) + var x72 uint64 + cmovznzU64(&x72, x3, arg5[2], x66) + var x73 uint64 + cmovznzU64(&x73, x3, arg5[3], x68) + x74 := (uint1(x22) & 0x1) + var x75 uint64 + cmovznzU64(&x75, x74, uint64(0x0), x7) + var x76 uint64 + cmovznzU64(&x76, x74, uint64(0x0), x8) + var x77 uint64 + cmovznzU64(&x77, x74, uint64(0x0), x9) + var x78 uint64 + cmovznzU64(&x78, x74, uint64(0x0), x10) + var x79 uint64 + cmovznzU64(&x79, x74, uint64(0x0), x11) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x22, x75, uint64(0x0)) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x23, x76, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x24, x77, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x25, x78, uint64(uint1(x85))) + var x88 uint64 + x88, _ = bits.Add64(x26, x79, uint64(uint1(x87))) + var x90 uint64 + cmovznzU64(&x90, x74, uint64(0x0), x27) + var x91 uint64 + cmovznzU64(&x91, x74, uint64(0x0), x28) + var x92 uint64 + cmovznzU64(&x92, x74, uint64(0x0), x29) + var x93 uint64 + cmovznzU64(&x93, x74, uint64(0x0), x30) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64(x70, x90, uint64(0x0)) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x71, x91, uint64(uint1(x95))) + var x98 uint64 + var x99 uint64 + x98, x99 = bits.Add64(x72, x92, uint64(uint1(x97))) + var x100 uint64 + var x101 uint64 + x100, x101 = bits.Add64(x73, x93, uint64(uint1(x99))) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Sub64(x94, 0xbfd25e8cd0364141, uint64(0x0)) + var x104 uint64 + var x105 uint64 + x104, x105 = bits.Sub64(x96, 0xbaaedce6af48a03b, uint64(uint1(x103))) + var x106 uint64 + var x107 uint64 + x106, x107 = bits.Sub64(x98, 0xfffffffffffffffe, uint64(uint1(x105))) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Sub64(x100, 0xffffffffffffffff, uint64(uint1(x107))) + var x111 uint64 + _, x111 = bits.Sub64(uint64(uint1(x101)), uint64(0x0), uint64(uint1(x109))) + var x112 uint64 + x112, _ = bits.Add64(x6, uint64(0x1), uint64(0x0)) + x114 := ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff)) + x115 := ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff)) + x116 := ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff)) + x117 := ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff)) + x118 := ((x88 & 0x8000000000000000) | (x88 >> 1)) + var x119 uint64 + cmovznzU64(&x119, uint1(x48), x39, x31) + var x120 uint64 + cmovznzU64(&x120, uint1(x48), x41, x33) + var x121 uint64 + cmovznzU64(&x121, uint1(x48), x43, x35) + var x122 uint64 + cmovznzU64(&x122, uint1(x48), x45, x37) + var x123 uint64 + cmovznzU64(&x123, uint1(x111), x102, x94) + var x124 uint64 + cmovznzU64(&x124, uint1(x111), x104, x96) + var x125 uint64 + cmovznzU64(&x125, uint1(x111), x106, x98) + var x126 uint64 + cmovznzU64(&x126, uint1(x111), x108, x100) + *out1 = x112 + out2[0] = x7 + out2[1] = x8 + out2[2] = x9 + out2[3] = x10 + out2[4] = x11 + out3[0] = x114 + out3[1] = x115 + out3[2] = x116 + out3[3] = x117 + out3[4] = x118 + out4[0] = x119 + out4[1] = x120 + out4[2] = x121 + out4[3] = x122 + out5[0] = x123 + out5[1] = x124 + out5[2] = x125 + out5[3] = x126 +} + +// DivstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form). +// +// Postconditions: +// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if ⌊log2 m⌋ + 1 < 46 then ⌊(49 * (⌊log2 m⌋ + 1) + 80) / 17⌋ else ⌊(49 * (⌊log2 m⌋ + 1) + 57) / 17⌋) +// 0 ≤ eval out1 < m +// +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func DivstepPrecomp(out1 *[4]uint64) { + out1[0] = 0xd7431a4d2b9cb4e9 + out1[1] = 0xab67d35a32d9c503 + out1[2] = 0xadf6c7e5859ce35f + out1[3] = 0x615441451df6c379 +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/point.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/point.go new file mode 100644 index 0000000000..583e3e24cc --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/k256/point.go @@ -0,0 +1,446 @@ +package k256 + +import ( + "sync" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp" +) + +var ( + k256PointInitonce sync.Once + k256PointParams native.EllipticPointParams + k256PointSswuInitOnce sync.Once + k256PointSswuParams native.SswuParams + k256PointIsogenyInitOnce sync.Once + k256PointIsogenyParams native.IsogenyParams +) + +func K256PointNew() *native.EllipticPoint { + return &native.EllipticPoint{ + X: fp.K256FpNew(), + Y: fp.K256FpNew(), + Z: fp.K256FpNew(), + Params: getK256PointParams(), + Arithmetic: &k256PointArithmetic{}, + } +} + +func k256PointParamsInit() { + k256PointParams = native.EllipticPointParams{ + A: fp.K256FpNew(), + B: fp.K256FpNew().SetUint64(7), + Gx: fp.K256FpNew().SetLimbs(&[native.FieldLimbs]uint64{ + 0x59f2815b16f81798, + 0x029bfcdb2dce28d9, + 0x55a06295ce870b07, + 0x79be667ef9dcbbac, + }), + Gy: fp.K256FpNew().SetLimbs(&[native.FieldLimbs]uint64{ + 0x9c47d08ffb10d4b8, + 0xfd17b448a6855419, + 0x5da4fbfc0e1108a8, + 0x483ada7726a3c465, + }), + BitSize: 256, + Name: "secp256k1", + } +} + +func getK256PointParams() *native.EllipticPointParams { + k256PointInitonce.Do(k256PointParamsInit) + return &k256PointParams +} + +func getK256PointSswuParams() *native.SswuParams { + k256PointSswuInitOnce.Do(k256PointSswuParamsInit) + return &k256PointSswuParams +} + +func k256PointSswuParamsInit() { + // Taken from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.7 + //params := btcec.S256().Params() + // + //// c1 = (q - 3) / 4 + //c1 := new(big.Int).Set(params.P) + //c1.Sub(c1, big.NewInt(3)) + //c1.Rsh(c1, 2) + // + //a, _ := new(big.Int).SetString("3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533", 16) + //b := big.NewInt(1771) + //z := big.NewInt(-11) + //z.Mod(z, params.P) + //// sqrt(-z^3) + //zTmp := new(big.Int).Exp(z, big.NewInt(3), nil) + //zTmp = zTmp.Neg(zTmp) + //zTmp.Mod(zTmp, params.P) + //c2 := new(big.Int).ModSqrt(zTmp, params.P) + // + //var tBytes [32]byte + //c1.FillBytes(tBytes[:]) + //newC1 := [native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(tBytes[24:32]), + // binary.BigEndian.Uint64(tBytes[16:24]), + // binary.BigEndian.Uint64(tBytes[8:16]), + // binary.BigEndian.Uint64(tBytes[:8]), + //} + //fp.K256FpNew().Arithmetic.ToMontgomery(&newC1, &newC1) + //c2.FillBytes(tBytes[:]) + //newC2 := [native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(tBytes[24:32]), + // binary.BigEndian.Uint64(tBytes[16:24]), + // binary.BigEndian.Uint64(tBytes[8:16]), + // binary.BigEndian.Uint64(tBytes[:8]), + //} + //fp.K256FpNew().Arithmetic.ToMontgomery(&newC2, &newC2) + //a.FillBytes(tBytes[:]) + //newA := [native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(tBytes[24:32]), + // binary.BigEndian.Uint64(tBytes[16:24]), + // binary.BigEndian.Uint64(tBytes[8:16]), + // binary.BigEndian.Uint64(tBytes[:8]), + //} + //fp.K256FpNew().Arithmetic.ToMontgomery(&newA, &newA) + //b.FillBytes(tBytes[:]) + //newB := [native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(tBytes[24:32]), + // binary.BigEndian.Uint64(tBytes[16:24]), + // binary.BigEndian.Uint64(tBytes[8:16]), + // binary.BigEndian.Uint64(tBytes[:8]), + //} + //fp.K256FpNew().Arithmetic.ToMontgomery(&newB, &newB) + //z.FillBytes(tBytes[:]) + //newZ := [native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(tBytes[24:32]), + // binary.BigEndian.Uint64(tBytes[16:24]), + // binary.BigEndian.Uint64(tBytes[8:16]), + // binary.BigEndian.Uint64(tBytes[:8]), + //} + //fp.K256FpNew().Arithmetic.ToMontgomery(&newZ, &newZ) + + k256PointSswuParams = native.SswuParams{ + // (q -3) // 4 + C1: [native.FieldLimbs]uint64{0xffffffffbfffff0b, 0xffffffffffffffff, 0xffffffffffffffff, 0x3fffffffffffffff}, + // sqrt(-z^3) + C2: [native.FieldLimbs]uint64{0x5b57ba53a30d1520, 0x908f7cef34a762eb, 0x190b0ffe068460c8, 0x98a9828e8f00ff62}, + // 0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533 + A: [native.FieldLimbs]uint64{0xdb714ce7b18444a1, 0x4458ce38a32a19a2, 0xa0e58ae2837bfbf0, 0x505aabc49336d959}, + // 1771 + B: [native.FieldLimbs]uint64{0x000006eb001a66db, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000}, + // -11 + Z: [native.FieldLimbs]uint64{0xfffffff3ffffd234, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}, + } +} + +func k256PointIsogenyInit() { + k256PointIsogenyParams = native.IsogenyParams{ + XNum: [][native.FieldLimbs]uint64{ + { + 0x0000003b1c72a8b4, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + { + 0xd5bd51a17b2edf46, + 0x2cc06f7c86b86bcd, + 0x50b37e74f3294a00, + 0xeb32314a9da73679, + }, + { + 0x48c18b1b0d2191bd, + 0x5a3f74c29bfccce3, + 0xbe55a02e5e8bd357, + 0x09bf218d11fff905, + }, + { + 0x000000001c71c789, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + XDen: [][native.FieldLimbs]uint64{ + { + 0x8af79c1ffdf1e7fa, + 0xb84bc22235735eb5, + 0x82ee5655a55ace04, + 0xce4b32dea0a2becb, + }, + { + 0x8ecde3f3762e1fa5, + 0x2c3b1ad77be333fd, + 0xb102a1a152ea6e12, + 0x57b82df5a1ffc133, + }, + { + 0x00000001000003d1, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + YNum: [][native.FieldLimbs]uint64{ + { + 0xffffffce425e12c3, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0xba60d5fd6e56922e, + 0x4ec198c898a435f2, + 0x27e77a577b9764ab, + 0xb3b80a1197651d12, + }, + { + 0xa460c58d0690c6f6, + 0xad1fba614dfe6671, + 0xdf2ad0172f45e9ab, + 0x84df90c688fffc82, + }, + { + 0x00000000097b4283, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + YDen: [][native.FieldLimbs]uint64{ + { + 0xfffffd0afff4b6fb, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + }, + { + 0xa0e6d461f9d5bf90, + 0x28e34666a05a1c20, + 0x88cb0300f0106a0e, + 0x6ae1989be1e83c62, + }, + { + 0x5634d5edb1453160, + 0x4258a84339d4cdfc, + 0x8983f271fc5fa51b, + 0x039444f072ffa1cd, + }, + { + 0x00000001000003d1, + 0x0000000000000000, + 0x0000000000000000, + 0x0000000000000000, + }, + }, + } +} + +func getK256PointIsogenyParams() *native.IsogenyParams { + k256PointIsogenyInitOnce.Do(k256PointIsogenyInit) + return &k256PointIsogenyParams +} + +type k256PointArithmetic struct{} + +func (k k256PointArithmetic) Hash(out *native.EllipticPoint, hash *native.EllipticPointHasher, msg, dst []byte) error { + var u []byte + sswuParams := getK256PointSswuParams() + isoParams := getK256PointIsogenyParams() + + switch hash.Type() { + case native.XMD: + u = native.ExpandMsgXmd(hash, msg, dst, 96) + case native.XOF: + u = native.ExpandMsgXof(hash, msg, dst, 96) + } + var buf [64]byte + copy(buf[:48], internal.ReverseScalarBytes(u[:48])) + u0 := fp.K256FpNew().SetBytesWide(&buf) + copy(buf[:48], internal.ReverseScalarBytes(u[48:])) + u1 := fp.K256FpNew().SetBytesWide(&buf) + + r0x, r0y := sswuParams.Osswu3mod4(u0) + r1x, r1y := sswuParams.Osswu3mod4(u1) + q0x, q0y := isoParams.Map(r0x, r0y) + q1x, q1y := isoParams.Map(r1x, r1y) + out.X = q0x + out.Y = q0y + out.Z.SetOne() + tv := &native.EllipticPoint{ + X: q1x, + Y: q1y, + Z: fp.K256FpNew().SetOne(), + } + k.Add(out, out, tv) + return nil +} + +func (k k256PointArithmetic) Double(out, arg *native.EllipticPoint) { + // Addition formula from Renes-Costello-Batina 2015 + // (https://eprint.iacr.org/2015/1060 Algorithm 9) + var yy, zz, xy2, bzz, bzz3, bzz9 [native.FieldLimbs]uint64 + var yyMBzz9, yyPBzz3, yyzz, yyzz8, t [native.FieldLimbs]uint64 + var x, y, z [native.FieldLimbs]uint64 + f := arg.X.Arithmetic + + f.Square(&yy, &arg.Y.Value) + f.Square(&zz, &arg.Z.Value) + f.Mul(&xy2, &arg.X.Value, &arg.Y.Value) + f.Add(&xy2, &xy2, &xy2) + f.Mul(&bzz, &zz, &arg.Params.B.Value) + f.Add(&bzz3, &bzz, &bzz) + f.Add(&bzz3, &bzz3, &bzz) + f.Add(&bzz9, &bzz3, &bzz3) + f.Add(&bzz9, &bzz9, &bzz3) + f.Neg(&yyMBzz9, &bzz9) + f.Add(&yyMBzz9, &yyMBzz9, &yy) + f.Add(&yyPBzz3, &yy, &bzz3) + f.Mul(&yyzz, &yy, &zz) + f.Add(&yyzz8, &yyzz, &yyzz) + f.Add(&yyzz8, &yyzz8, &yyzz8) + f.Add(&yyzz8, &yyzz8, &yyzz8) + f.Add(&t, &yyzz8, &yyzz8) + f.Add(&t, &t, &yyzz8) + f.Mul(&t, &t, &arg.Params.B.Value) + + f.Mul(&x, &xy2, &yyMBzz9) + + f.Mul(&y, &yyMBzz9, &yyPBzz3) + f.Add(&y, &y, &t) + + f.Mul(&z, &yy, &arg.Y.Value) + f.Mul(&z, &z, &arg.Z.Value) + f.Add(&z, &z, &z) + f.Add(&z, &z, &z) + f.Add(&z, &z, &z) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z +} + +func (k k256PointArithmetic) Add(out, arg1, arg2 *native.EllipticPoint) { + // Addition formula from Renes-Costello-Batina 2015 + // (https://eprint.iacr.org/2015/1060 Algorithm 7). + var xx, yy, zz, nXxYy, nYyZz, nXxZz [native.FieldLimbs]uint64 + var tv1, tv2, xyPairs, yzPairs, xzPairs [native.FieldLimbs]uint64 + var bzz, bzz3, yyMBzz3, yyPBzz3, byz [native.FieldLimbs]uint64 + var byz3, xx3, bxx9, x, y, z [native.FieldLimbs]uint64 + f := arg1.X.Arithmetic + + f.Mul(&xx, &arg1.X.Value, &arg2.X.Value) + f.Mul(&yy, &arg1.Y.Value, &arg2.Y.Value) + f.Mul(&zz, &arg1.Z.Value, &arg2.Z.Value) + + f.Add(&nXxYy, &xx, &yy) + f.Neg(&nXxYy, &nXxYy) + + f.Add(&nYyZz, &yy, &zz) + f.Neg(&nYyZz, &nYyZz) + + f.Add(&nXxZz, &xx, &zz) + f.Neg(&nXxZz, &nXxZz) + + f.Add(&tv1, &arg1.X.Value, &arg1.Y.Value) + f.Add(&tv2, &arg2.X.Value, &arg2.Y.Value) + f.Mul(&xyPairs, &tv1, &tv2) + f.Add(&xyPairs, &xyPairs, &nXxYy) + + f.Add(&tv1, &arg1.Y.Value, &arg1.Z.Value) + f.Add(&tv2, &arg2.Y.Value, &arg2.Z.Value) + f.Mul(&yzPairs, &tv1, &tv2) + f.Add(&yzPairs, &yzPairs, &nYyZz) + + f.Add(&tv1, &arg1.X.Value, &arg1.Z.Value) + f.Add(&tv2, &arg2.X.Value, &arg2.Z.Value) + f.Mul(&xzPairs, &tv1, &tv2) + f.Add(&xzPairs, &xzPairs, &nXxZz) + + f.Mul(&bzz, &zz, &arg1.Params.B.Value) + f.Add(&bzz3, &bzz, &bzz) + f.Add(&bzz3, &bzz3, &bzz) + + f.Neg(&yyMBzz3, &bzz3) + f.Add(&yyMBzz3, &yyMBzz3, &yy) + + f.Add(&yyPBzz3, &yy, &bzz3) + + f.Mul(&byz, &yzPairs, &arg1.Params.B.Value) + f.Add(&byz3, &byz, &byz) + f.Add(&byz3, &byz3, &byz) + + f.Add(&xx3, &xx, &xx) + f.Add(&xx3, &xx3, &xx) + + f.Add(&bxx9, &xx3, &xx3) + f.Add(&bxx9, &bxx9, &xx3) + f.Mul(&bxx9, &bxx9, &arg1.Params.B.Value) + + f.Mul(&tv1, &xyPairs, &yyMBzz3) + f.Mul(&tv2, &byz3, &xzPairs) + f.Neg(&tv2, &tv2) + f.Add(&x, &tv1, &tv2) + + f.Mul(&tv1, &yyPBzz3, &yyMBzz3) + f.Mul(&tv2, &bxx9, &xzPairs) + f.Add(&y, &tv1, &tv2) + + f.Mul(&tv1, &yzPairs, &yyPBzz3) + f.Mul(&tv2, &xx3, &xyPairs) + f.Add(&z, &tv1, &tv2) + + e1 := arg1.Z.IsZero() + e2 := arg2.Z.IsZero() + + // If arg1 is identity set it to arg2 + f.Selectznz(&z, &z, &arg2.Z.Value, e1) + f.Selectznz(&y, &y, &arg2.Y.Value, e1) + f.Selectznz(&x, &x, &arg2.X.Value, e1) + // If arg2 is identity set it to arg1 + f.Selectznz(&z, &z, &arg1.Z.Value, e2) + f.Selectznz(&y, &y, &arg1.Y.Value, e2) + f.Selectznz(&x, &x, &arg1.X.Value, e2) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z +} + +func (k k256PointArithmetic) IsOnCurve(arg *native.EllipticPoint) bool { + affine := K256PointNew() + k.ToAffine(affine, arg) + lhs := fp.K256FpNew().Square(affine.Y) + rhs := fp.K256FpNew() + k.RhsEq(rhs, affine.X) + return lhs.Equal(rhs) == 1 +} + +func (k k256PointArithmetic) ToAffine(out, arg *native.EllipticPoint) { + var wasInverted int + var zero, x, y, z [native.FieldLimbs]uint64 + f := arg.X.Arithmetic + + f.Invert(&wasInverted, &z, &arg.Z.Value) + f.Mul(&x, &arg.X.Value, &z) + f.Mul(&y, &arg.Y.Value, &z) + + out.Z.SetOne() + // If point at infinity this does nothing + f.Selectznz(&x, &zero, &x, wasInverted) + f.Selectznz(&y, &zero, &y, wasInverted) + f.Selectznz(&z, &zero, &out.Z.Value, wasInverted) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z + out.Params = arg.Params + out.Arithmetic = arg.Arithmetic +} + +func (k k256PointArithmetic) RhsEq(out, x *native.Field) { + // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7 + out.Square(x) + out.Mul(out, x) + out.Add(out, getK256PointParams().B) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/osswu.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/osswu.go new file mode 100644 index 0000000000..ba867f3519 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/osswu.go @@ -0,0 +1,82 @@ +package native + +// SswuParams for computing the Simplified SWU mapping +// for hash to curve implementations +type SswuParams struct { + C1, C2, A, B, Z [FieldLimbs]uint64 +} + +// Osswu3mod4 computes the simplified map optmized for 3 mod 4 primes +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.2.1 +func (p *SswuParams) Osswu3mod4(u *Field) (x, y *Field) { + var tv1, tv2, tv3, tv4, xd, x1n, x2n, gxd, gx1, aNeg, zA, y1, y2 [FieldLimbs]uint64 + var wasInverted int + u.Arithmetic.Mul(&tv1, &u.Value, &u.Value) // tv1 = u^2 + u.Arithmetic.Mul(&tv3, &p.Z, &tv1) // tv3 = z * tv1 + u.Arithmetic.Square(&tv2, &tv3) // tv2 = tv3^2 + u.Arithmetic.Add(&xd, &tv2, &tv3) // xd = tv2 + tv3 + u.Arithmetic.Add(&x1n, &u.Params.R, &xd) // x1n = (xd + 1) + u.Arithmetic.Mul(&x1n, &x1n, &p.B) // x1n * B + u.Arithmetic.Neg(&aNeg, &p.A) + u.Arithmetic.Mul(&xd, &xd, &aNeg) // xd = -A * xd + + xdIsZero := (&Field{ + Value: xd, + }).IsZero() + u.Arithmetic.Mul(&zA, &p.Z, &p.A) + u.Arithmetic.Selectznz(&xd, &xd, &zA, xdIsZero) // xd = z * A if xd == 0 + + u.Arithmetic.Square(&tv2, &xd) // tv2 = xd^2 + u.Arithmetic.Mul(&gxd, &tv2, &xd) // gxd = tv2 * xd + u.Arithmetic.Mul(&tv2, &tv2, &p.A) // tv2 = A * tv2 + + u.Arithmetic.Square(&gx1, &x1n) // gx1 = x1n^2 + u.Arithmetic.Add(&gx1, &gx1, &tv2) // gx1 = gx1 + tv2 + u.Arithmetic.Mul(&gx1, &gx1, &x1n) // gx1 = gx1 * x1n + u.Arithmetic.Mul(&tv2, &gxd, &p.B) // tv2 = B * gxd + u.Arithmetic.Add(&gx1, &gx1, &tv2) // gx1 = gx1 + tv2 + + u.Arithmetic.Square(&tv4, &gxd) // tv4 = gxd^2 + u.Arithmetic.Mul(&tv2, &gx1, &gxd) // tv2 = gx1 * gxd + u.Arithmetic.Mul(&tv4, &tv4, &tv2) // tv4 = tv4 * tv2 + + Pow(&y1, &tv4, &p.C1, u.Params, u.Arithmetic) // y1 = tv4^C1 + u.Arithmetic.Mul(&y1, &y1, &tv2) //y1 = y1 * tv2 + u.Arithmetic.Mul(&x2n, &tv3, &x1n) // x2n = tv3 * x1n + + u.Arithmetic.Mul(&y2, &y1, &p.C2) // y2 = y1 * c2 + u.Arithmetic.Mul(&y2, &y2, &tv1) // y2 = y2 * tv1 + u.Arithmetic.Mul(&y2, &y2, &u.Value) // y2 = y2 * u + + u.Arithmetic.Square(&tv2, &y1) // tv2 = y1^2 + u.Arithmetic.Mul(&tv2, &tv2, &gxd) // tv2 = tv2 * gxd + + e2 := (&Field{Value: tv2}).Equal(&Field{Value: gx1}) + + x = new(Field).Set(u) + y = new(Field).Set(u) + + // If e2, x = x1, else x = x2 + u.Arithmetic.Selectznz(&x.Value, &x2n, &x1n, e2) + + // xn / xd + u.Arithmetic.Invert(&wasInverted, &tv1, &xd) + u.Arithmetic.Mul(&tv1, &x.Value, &tv1) + u.Arithmetic.Selectznz(&x.Value, &x.Value, &tv1, wasInverted) + + // If e2, y = y1, else y = y2 + u.Arithmetic.Selectznz(&y.Value, &y2, &y1, e2) + + uBytes := u.Bytes() + yBytes := y.Bytes() + + usign := uBytes[0] & 1 + ysign := yBytes[0] & 1 + + // Fix sign of y + if usign != ysign { + y.Neg(y) + } + + return +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/fp.go new file mode 100644 index 0000000000..a115b4243c --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/fp.go @@ -0,0 +1,169 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fp + +import ( + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var p256FpInitonce sync.Once +var p256FpParams native.FieldParams + +func P256FpNew() *native.Field { + return &native.Field{ + Value: [native.FieldLimbs]uint64{}, + Params: getP256FpParams(), + Arithmetic: p256FpArithmetic{}, + } +} + +func p256FpParamsInit() { + // See FIPS 186-3, section D.2.3 + p256FpParams = native.FieldParams{ + R: [native.FieldLimbs]uint64{0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe}, + R2: [native.FieldLimbs]uint64{0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd}, + R3: [native.FieldLimbs]uint64{0xfffffffd0000000a, 0xffffffedfffffff7, 0x00000005fffffffc, 0x0000001800000001}, + Modulus: [native.FieldLimbs]uint64{0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001}, + BiModulus: new(big.Int).SetBytes([]byte{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), + } +} + +func getP256FpParams() *native.FieldParams { + p256FpInitonce.Do(p256FpParamsInit) + return &p256FpParams +} + +// p256FpArithmetic is a struct with all the methods needed for working +// in mod q +type p256FpArithmetic struct{} + +// ToMontgomery converts this field to montgomery form +func (f p256FpArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) { + ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg)) +} + +// FromMontgomery converts this field from montgomery form +func (f p256FpArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) { + FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Neg performs modular negation +func (f p256FpArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) { + Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Square performs modular square +func (f p256FpArithmetic) Square(out, arg *[native.FieldLimbs]uint64) { + Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Mul performs modular multiplication +func (f p256FpArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Add performs modular addition +func (f p256FpArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sub performs modular subtraction +func (f p256FpArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sqrt performs modular square root +func (f p256FpArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) { + // Use p = 3 mod 4 by Euler's criterion means + // arg^((p+1)/4 mod p + var t, c [native.FieldLimbs]uint64 + c1 := [native.FieldLimbs]uint64{ + 0x0000_0000_0000_0000, + 0x0000_0000_4000_0000, + 0x4000_0000_0000_0000, + 0x3fff_ffff_c000_0000, + } + native.Pow(&t, arg, &c1, getP256FpParams(), f) + Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&t)) + *wasSquare = (&native.Field{Value: c, Params: getP256FpParams(), Arithmetic: f}).Equal(&native.Field{ + Value: *arg, Params: getP256FpParams(), Arithmetic: f, + }) + Selectznz(out, uint1(*wasSquare), out, &t) +} + +// Invert performs modular inverse +func (f p256FpArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) { + // Fermat's Little Theorem + // a ^ (p - 2) mod p + // + // The exponent pattern (from high to low) is: + // - 32 bits of value 1 + // - 31 bits of value 0 + // - 1 bit of value 1 + // - 96 bits of value 0 + // - 94 bits of value 1 + // - 1 bit of value 0 + // - 1 bit of value 1 + // To speed up the square-and-multiply algorithm, precompute a^(2^31-1). + // + // Courtesy of Thomas Pornin + // + var t, r [native.FieldLimbs]uint64 + copy(t[:], arg[:]) + + for i := 0; i < 30; i++ { + f.Square(&t, &t) + f.Mul(&t, &t, arg) + } + copy(r[:], t[:]) + for i := 224; i >= 0; i-- { + f.Square(&r, &r) + switch i { + case 0: + fallthrough + case 2: + fallthrough + case 192: + fallthrough + case 224: + f.Mul(&r, &r, arg) + case 3: + fallthrough + case 34: + fallthrough + case 65: + f.Mul(&r, &r, &t) + } + } + + *wasInverted = (&native.Field{ + Value: *arg, + Params: getP256FpParams(), + Arithmetic: f, + }).IsNonZero() + Selectznz(out, uint1(*wasInverted), out, &r) +} + +// FromBytes converts a little endian byte array into a field element +func (f p256FpArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) { + FromBytes(out, arg) +} + +// ToBytes converts a field element to a little endian byte array +func (f p256FpArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) { + ToBytes(out, arg) +} + +// Selectznz performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f p256FpArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) { + Selectznz(out, uint1(choice), arg1, arg2) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/p256_fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/p256_fp.go new file mode 100644 index 0000000000..6306a71275 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp/p256_fp.go @@ -0,0 +1,1427 @@ +// Code generated by Fiat Cryptography. DO NOT EDIT. +// +// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --internal-static --package-case flatcase --public-function-case UpperCamelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case camelCase --no-prefix-fiat --doc-newline-in-typedef-bounds --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-text-before-function-name '' --doc-text-before-type-name '' --package-name p256 '' 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one +// +// curve description (via package name): p256 +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp +// +// m = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff (from "2^256 - 2^224 + 2^192 + 2^96 - 1") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 +package fp + +import "math/bits" + +type uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// MontgomeryDomainFieldElement is a field element in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type MontgomeryDomainFieldElement [4]uint64 + +// NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type NonMontgomeryDomainFieldElement [4]uint64 + +// cmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func cmovznzU64(out1 *uint64, arg1 uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// Mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Mul(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(x11, 0xffffffff00000001) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x11, 0xffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x11, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(x25, x22, uint64(0x0)) + x28 := (uint64(uint1(x27)) + x23) + var x30 uint64 + _, x30 = bits.Add64(x11, x24, uint64(0x0)) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x13, x26, uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x15, x28, uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64(x17, x20, uint64(uint1(x34))) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x19, x21, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(x1, arg2[3]) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg2[2]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg2[1]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg2[0]) + var x47 uint64 + var x48 uint64 + x47, x48 = bits.Add64(x46, x43, uint64(0x0)) + var x49 uint64 + var x50 uint64 + x49, x50 = bits.Add64(x44, x41, uint64(uint1(x48))) + var x51 uint64 + var x52 uint64 + x51, x52 = bits.Add64(x42, x39, uint64(uint1(x50))) + x53 := (uint64(uint1(x52)) + x40) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64(x31, x45, uint64(0x0)) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x33, x47, uint64(uint1(x55))) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x35, x49, uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64(x37, x51, uint64(uint1(x59))) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(uint64(uint1(x38)), x53, uint64(uint1(x61))) + var x64 uint64 + var x65 uint64 + x65, x64 = bits.Mul64(x54, 0xffffffff00000001) + var x66 uint64 + var x67 uint64 + x67, x66 = bits.Mul64(x54, 0xffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x54, 0xffffffffffffffff) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(x69, x66, uint64(0x0)) + x72 := (uint64(uint1(x71)) + x67) + var x74 uint64 + _, x74 = bits.Add64(x54, x68, uint64(0x0)) + var x75 uint64 + var x76 uint64 + x75, x76 = bits.Add64(x56, x70, uint64(uint1(x74))) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x58, x72, uint64(uint1(x76))) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x60, x64, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x62, x65, uint64(uint1(x80))) + x83 := (uint64(uint1(x82)) + uint64(uint1(x63))) + var x84 uint64 + var x85 uint64 + x85, x84 = bits.Mul64(x2, arg2[3]) + var x86 uint64 + var x87 uint64 + x87, x86 = bits.Mul64(x2, arg2[2]) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg2[1]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg2[0]) + var x92 uint64 + var x93 uint64 + x92, x93 = bits.Add64(x91, x88, uint64(0x0)) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64(x89, x86, uint64(uint1(x93))) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x87, x84, uint64(uint1(x95))) + x98 := (uint64(uint1(x97)) + x85) + var x99 uint64 + var x100 uint64 + x99, x100 = bits.Add64(x75, x90, uint64(0x0)) + var x101 uint64 + var x102 uint64 + x101, x102 = bits.Add64(x77, x92, uint64(uint1(x100))) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x79, x94, uint64(uint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x81, x96, uint64(uint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x83, x98, uint64(uint1(x106))) + var x109 uint64 + var x110 uint64 + x110, x109 = bits.Mul64(x99, 0xffffffff00000001) + var x111 uint64 + var x112 uint64 + x112, x111 = bits.Mul64(x99, 0xffffffff) + var x113 uint64 + var x114 uint64 + x114, x113 = bits.Mul64(x99, 0xffffffffffffffff) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x114, x111, uint64(0x0)) + x117 := (uint64(uint1(x116)) + x112) + var x119 uint64 + _, x119 = bits.Add64(x99, x113, uint64(0x0)) + var x120 uint64 + var x121 uint64 + x120, x121 = bits.Add64(x101, x115, uint64(uint1(x119))) + var x122 uint64 + var x123 uint64 + x122, x123 = bits.Add64(x103, x117, uint64(uint1(x121))) + var x124 uint64 + var x125 uint64 + x124, x125 = bits.Add64(x105, x109, uint64(uint1(x123))) + var x126 uint64 + var x127 uint64 + x126, x127 = bits.Add64(x107, x110, uint64(uint1(x125))) + x128 := (uint64(uint1(x127)) + uint64(uint1(x108))) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x3, arg2[3]) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x3, arg2[2]) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x3, arg2[1]) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg2[0]) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x136, x133, uint64(0x0)) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x134, x131, uint64(uint1(x138))) + var x141 uint64 + var x142 uint64 + x141, x142 = bits.Add64(x132, x129, uint64(uint1(x140))) + x143 := (uint64(uint1(x142)) + x130) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x120, x135, uint64(0x0)) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x122, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x124, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x126, x141, uint64(uint1(x149))) + var x152 uint64 + var x153 uint64 + x152, x153 = bits.Add64(x128, x143, uint64(uint1(x151))) + var x154 uint64 + var x155 uint64 + x155, x154 = bits.Mul64(x144, 0xffffffff00000001) + var x156 uint64 + var x157 uint64 + x157, x156 = bits.Mul64(x144, 0xffffffff) + var x158 uint64 + var x159 uint64 + x159, x158 = bits.Mul64(x144, 0xffffffffffffffff) + var x160 uint64 + var x161 uint64 + x160, x161 = bits.Add64(x159, x156, uint64(0x0)) + x162 := (uint64(uint1(x161)) + x157) + var x164 uint64 + _, x164 = bits.Add64(x144, x158, uint64(0x0)) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x146, x160, uint64(uint1(x164))) + var x167 uint64 + var x168 uint64 + x167, x168 = bits.Add64(x148, x162, uint64(uint1(x166))) + var x169 uint64 + var x170 uint64 + x169, x170 = bits.Add64(x150, x154, uint64(uint1(x168))) + var x171 uint64 + var x172 uint64 + x171, x172 = bits.Add64(x152, x155, uint64(uint1(x170))) + x173 := (uint64(uint1(x172)) + uint64(uint1(x153))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Sub64(x165, 0xffffffffffffffff, uint64(0x0)) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Sub64(x167, 0xffffffff, uint64(uint1(x175))) + var x178 uint64 + var x179 uint64 + x178, x179 = bits.Sub64(x169, uint64(0x0), uint64(uint1(x177))) + var x180 uint64 + var x181 uint64 + x180, x181 = bits.Sub64(x171, 0xffffffff00000001, uint64(uint1(x179))) + var x183 uint64 + _, x183 = bits.Sub64(x173, uint64(0x0), uint64(uint1(x181))) + var x184 uint64 + cmovznzU64(&x184, uint1(x183), x174, x165) + var x185 uint64 + cmovznzU64(&x185, uint1(x183), x176, x167) + var x186 uint64 + cmovznzU64(&x186, uint1(x183), x178, x169) + var x187 uint64 + cmovznzU64(&x187, uint1(x183), x180, x171) + out1[0] = x184 + out1[1] = x185 + out1[2] = x186 + out1[3] = x187 +} + +// Square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func Square(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(x11, 0xffffffff00000001) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x11, 0xffffffff) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x11, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(x25, x22, uint64(0x0)) + x28 := (uint64(uint1(x27)) + x23) + var x30 uint64 + _, x30 = bits.Add64(x11, x24, uint64(0x0)) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x13, x26, uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x15, x28, uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64(x17, x20, uint64(uint1(x34))) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x19, x21, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(x1, arg1[3]) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg1[2]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg1[1]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg1[0]) + var x47 uint64 + var x48 uint64 + x47, x48 = bits.Add64(x46, x43, uint64(0x0)) + var x49 uint64 + var x50 uint64 + x49, x50 = bits.Add64(x44, x41, uint64(uint1(x48))) + var x51 uint64 + var x52 uint64 + x51, x52 = bits.Add64(x42, x39, uint64(uint1(x50))) + x53 := (uint64(uint1(x52)) + x40) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64(x31, x45, uint64(0x0)) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x33, x47, uint64(uint1(x55))) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x35, x49, uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64(x37, x51, uint64(uint1(x59))) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(uint64(uint1(x38)), x53, uint64(uint1(x61))) + var x64 uint64 + var x65 uint64 + x65, x64 = bits.Mul64(x54, 0xffffffff00000001) + var x66 uint64 + var x67 uint64 + x67, x66 = bits.Mul64(x54, 0xffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x54, 0xffffffffffffffff) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(x69, x66, uint64(0x0)) + x72 := (uint64(uint1(x71)) + x67) + var x74 uint64 + _, x74 = bits.Add64(x54, x68, uint64(0x0)) + var x75 uint64 + var x76 uint64 + x75, x76 = bits.Add64(x56, x70, uint64(uint1(x74))) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x58, x72, uint64(uint1(x76))) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x60, x64, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x62, x65, uint64(uint1(x80))) + x83 := (uint64(uint1(x82)) + uint64(uint1(x63))) + var x84 uint64 + var x85 uint64 + x85, x84 = bits.Mul64(x2, arg1[3]) + var x86 uint64 + var x87 uint64 + x87, x86 = bits.Mul64(x2, arg1[2]) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg1[1]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg1[0]) + var x92 uint64 + var x93 uint64 + x92, x93 = bits.Add64(x91, x88, uint64(0x0)) + var x94 uint64 + var x95 uint64 + x94, x95 = bits.Add64(x89, x86, uint64(uint1(x93))) + var x96 uint64 + var x97 uint64 + x96, x97 = bits.Add64(x87, x84, uint64(uint1(x95))) + x98 := (uint64(uint1(x97)) + x85) + var x99 uint64 + var x100 uint64 + x99, x100 = bits.Add64(x75, x90, uint64(0x0)) + var x101 uint64 + var x102 uint64 + x101, x102 = bits.Add64(x77, x92, uint64(uint1(x100))) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x79, x94, uint64(uint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x81, x96, uint64(uint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x83, x98, uint64(uint1(x106))) + var x109 uint64 + var x110 uint64 + x110, x109 = bits.Mul64(x99, 0xffffffff00000001) + var x111 uint64 + var x112 uint64 + x112, x111 = bits.Mul64(x99, 0xffffffff) + var x113 uint64 + var x114 uint64 + x114, x113 = bits.Mul64(x99, 0xffffffffffffffff) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x114, x111, uint64(0x0)) + x117 := (uint64(uint1(x116)) + x112) + var x119 uint64 + _, x119 = bits.Add64(x99, x113, uint64(0x0)) + var x120 uint64 + var x121 uint64 + x120, x121 = bits.Add64(x101, x115, uint64(uint1(x119))) + var x122 uint64 + var x123 uint64 + x122, x123 = bits.Add64(x103, x117, uint64(uint1(x121))) + var x124 uint64 + var x125 uint64 + x124, x125 = bits.Add64(x105, x109, uint64(uint1(x123))) + var x126 uint64 + var x127 uint64 + x126, x127 = bits.Add64(x107, x110, uint64(uint1(x125))) + x128 := (uint64(uint1(x127)) + uint64(uint1(x108))) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x3, arg1[3]) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x3, arg1[2]) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x3, arg1[1]) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg1[0]) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x136, x133, uint64(0x0)) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x134, x131, uint64(uint1(x138))) + var x141 uint64 + var x142 uint64 + x141, x142 = bits.Add64(x132, x129, uint64(uint1(x140))) + x143 := (uint64(uint1(x142)) + x130) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x120, x135, uint64(0x0)) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x122, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x124, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x126, x141, uint64(uint1(x149))) + var x152 uint64 + var x153 uint64 + x152, x153 = bits.Add64(x128, x143, uint64(uint1(x151))) + var x154 uint64 + var x155 uint64 + x155, x154 = bits.Mul64(x144, 0xffffffff00000001) + var x156 uint64 + var x157 uint64 + x157, x156 = bits.Mul64(x144, 0xffffffff) + var x158 uint64 + var x159 uint64 + x159, x158 = bits.Mul64(x144, 0xffffffffffffffff) + var x160 uint64 + var x161 uint64 + x160, x161 = bits.Add64(x159, x156, uint64(0x0)) + x162 := (uint64(uint1(x161)) + x157) + var x164 uint64 + _, x164 = bits.Add64(x144, x158, uint64(0x0)) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x146, x160, uint64(uint1(x164))) + var x167 uint64 + var x168 uint64 + x167, x168 = bits.Add64(x148, x162, uint64(uint1(x166))) + var x169 uint64 + var x170 uint64 + x169, x170 = bits.Add64(x150, x154, uint64(uint1(x168))) + var x171 uint64 + var x172 uint64 + x171, x172 = bits.Add64(x152, x155, uint64(uint1(x170))) + x173 := (uint64(uint1(x172)) + uint64(uint1(x153))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Sub64(x165, 0xffffffffffffffff, uint64(0x0)) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Sub64(x167, 0xffffffff, uint64(uint1(x175))) + var x178 uint64 + var x179 uint64 + x178, x179 = bits.Sub64(x169, uint64(0x0), uint64(uint1(x177))) + var x180 uint64 + var x181 uint64 + x180, x181 = bits.Sub64(x171, 0xffffffff00000001, uint64(uint1(x179))) + var x183 uint64 + _, x183 = bits.Sub64(x173, uint64(0x0), uint64(uint1(x181))) + var x184 uint64 + cmovznzU64(&x184, uint1(x183), x174, x165) + var x185 uint64 + cmovznzU64(&x185, uint1(x183), x176, x167) + var x186 uint64 + cmovznzU64(&x186, uint1(x183), x178, x169) + var x187 uint64 + cmovznzU64(&x187, uint1(x183), x180, x171) + out1[0] = x184 + out1[1] = x185 + out1[2] = x186 + out1[3] = x187 +} + +// Add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Add(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + var x10 uint64 + x9, x10 = bits.Sub64(x1, 0xffffffffffffffff, uint64(0x0)) + var x11 uint64 + var x12 uint64 + x11, x12 = bits.Sub64(x3, 0xffffffff, uint64(uint1(x10))) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(uint1(x12))) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Sub64(x7, 0xffffffff00000001, uint64(uint1(x14))) + var x18 uint64 + _, x18 = bits.Sub64(uint64(uint1(x8)), uint64(0x0), uint64(uint1(x16))) + var x19 uint64 + cmovznzU64(&x19, uint1(x18), x9, x1) + var x20 uint64 + cmovznzU64(&x20, uint1(x18), x11, x3) + var x21 uint64 + cmovznzU64(&x21, uint1(x18), x13, x5) + var x22 uint64 + cmovznzU64(&x22, uint1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// Sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Sub(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, x9, uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xffffffff), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, uint64(0x0), uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, (x9 & 0xffffffff00000001), uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// Opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func Opp(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, x9, uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xffffffff), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, uint64(0x0), uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, (x9 & 0xffffffff00000001), uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// FromMontgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func FromMontgomery(out1 *NonMontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[0] + var x2 uint64 + var x3 uint64 + x3, x2 = bits.Mul64(x1, 0xffffffff00000001) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x1, 0xffffffff) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x1, 0xffffffffffffffff) + var x8 uint64 + var x9 uint64 + x8, x9 = bits.Add64(x7, x4, uint64(0x0)) + var x11 uint64 + _, x11 = bits.Add64(x1, x6, uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(uint64(0x0), x8, uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x12, arg1[1], uint64(0x0)) + var x16 uint64 + var x17 uint64 + x17, x16 = bits.Mul64(x14, 0xffffffff00000001) + var x18 uint64 + var x19 uint64 + x19, x18 = bits.Mul64(x14, 0xffffffff) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(x14, 0xffffffffffffffff) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(x21, x18, uint64(0x0)) + var x25 uint64 + _, x25 = bits.Add64(x14, x20, uint64(0x0)) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64((uint64(uint1(x15)) + (uint64(uint1(x13)) + (uint64(uint1(x9)) + x5))), x22, uint64(uint1(x25))) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x2, (uint64(uint1(x23)) + x19), uint64(uint1(x27))) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x3, x16, uint64(uint1(x29))) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x26, arg1[2], uint64(0x0)) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x28, uint64(0x0), uint64(uint1(x33))) + var x36 uint64 + var x37 uint64 + x36, x37 = bits.Add64(x30, uint64(0x0), uint64(uint1(x35))) + var x38 uint64 + var x39 uint64 + x39, x38 = bits.Mul64(x32, 0xffffffff00000001) + var x40 uint64 + var x41 uint64 + x41, x40 = bits.Mul64(x32, 0xffffffff) + var x42 uint64 + var x43 uint64 + x43, x42 = bits.Mul64(x32, 0xffffffffffffffff) + var x44 uint64 + var x45 uint64 + x44, x45 = bits.Add64(x43, x40, uint64(0x0)) + var x47 uint64 + _, x47 = bits.Add64(x32, x42, uint64(0x0)) + var x48 uint64 + var x49 uint64 + x48, x49 = bits.Add64(x34, x44, uint64(uint1(x47))) + var x50 uint64 + var x51 uint64 + x50, x51 = bits.Add64(x36, (uint64(uint1(x45)) + x41), uint64(uint1(x49))) + var x52 uint64 + var x53 uint64 + x52, x53 = bits.Add64((uint64(uint1(x37)) + (uint64(uint1(x31)) + x17)), x38, uint64(uint1(x51))) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64(x48, arg1[3], uint64(0x0)) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x50, uint64(0x0), uint64(uint1(x55))) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x52, uint64(0x0), uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x61, x60 = bits.Mul64(x54, 0xffffffff00000001) + var x62 uint64 + var x63 uint64 + x63, x62 = bits.Mul64(x54, 0xffffffff) + var x64 uint64 + var x65 uint64 + x65, x64 = bits.Mul64(x54, 0xffffffffffffffff) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x65, x62, uint64(0x0)) + var x69 uint64 + _, x69 = bits.Add64(x54, x64, uint64(0x0)) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(x56, x66, uint64(uint1(x69))) + var x72 uint64 + var x73 uint64 + x72, x73 = bits.Add64(x58, (uint64(uint1(x67)) + x63), uint64(uint1(x71))) + var x74 uint64 + var x75 uint64 + x74, x75 = bits.Add64((uint64(uint1(x59)) + (uint64(uint1(x53)) + x39)), x60, uint64(uint1(x73))) + x76 := (uint64(uint1(x75)) + x61) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Sub64(x70, 0xffffffffffffffff, uint64(0x0)) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Sub64(x72, 0xffffffff, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Sub64(x74, uint64(0x0), uint64(uint1(x80))) + var x83 uint64 + var x84 uint64 + x83, x84 = bits.Sub64(x76, 0xffffffff00000001, uint64(uint1(x82))) + var x86 uint64 + _, x86 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(uint1(x84))) + var x87 uint64 + cmovznzU64(&x87, uint1(x86), x77, x70) + var x88 uint64 + cmovznzU64(&x88, uint1(x86), x79, x72) + var x89 uint64 + cmovznzU64(&x89, uint1(x86), x81, x74) + var x90 uint64 + cmovznzU64(&x90, uint1(x86), x83, x76) + out1[0] = x87 + out1[1] = x88 + out1[2] = x89 + out1[3] = x90 +} + +// ToMontgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func ToMontgomery(out1 *MontgomeryDomainFieldElement, arg1 *NonMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x4fffffffd) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0xfffffffffffffffe) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0xfffffffbffffffff) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0x3) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + var x19 uint64 + var x20 uint64 + x20, x19 = bits.Mul64(x11, 0xffffffff00000001) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x11, 0xffffffff) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x11, 0xffffffffffffffff) + var x25 uint64 + var x26 uint64 + x25, x26 = bits.Add64(x24, x21, uint64(0x0)) + var x28 uint64 + _, x28 = bits.Add64(x11, x23, uint64(0x0)) + var x29 uint64 + var x30 uint64 + x29, x30 = bits.Add64(x13, x25, uint64(uint1(x28))) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x15, (uint64(uint1(x26)) + x22), uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x17, x19, uint64(uint1(x32))) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64((uint64(uint1(x18)) + x6), x20, uint64(uint1(x34))) + var x37 uint64 + var x38 uint64 + x38, x37 = bits.Mul64(x1, 0x4fffffffd) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(x1, 0xfffffffffffffffe) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, 0xfffffffbffffffff) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, 0x3) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x44, x41, uint64(0x0)) + var x47 uint64 + var x48 uint64 + x47, x48 = bits.Add64(x42, x39, uint64(uint1(x46))) + var x49 uint64 + var x50 uint64 + x49, x50 = bits.Add64(x40, x37, uint64(uint1(x48))) + var x51 uint64 + var x52 uint64 + x51, x52 = bits.Add64(x29, x43, uint64(0x0)) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x31, x45, uint64(uint1(x52))) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x33, x47, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x35, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x60, x59 = bits.Mul64(x51, 0xffffffff00000001) + var x61 uint64 + var x62 uint64 + x62, x61 = bits.Mul64(x51, 0xffffffff) + var x63 uint64 + var x64 uint64 + x64, x63 = bits.Mul64(x51, 0xffffffffffffffff) + var x65 uint64 + var x66 uint64 + x65, x66 = bits.Add64(x64, x61, uint64(0x0)) + var x68 uint64 + _, x68 = bits.Add64(x51, x63, uint64(0x0)) + var x69 uint64 + var x70 uint64 + x69, x70 = bits.Add64(x53, x65, uint64(uint1(x68))) + var x71 uint64 + var x72 uint64 + x71, x72 = bits.Add64(x55, (uint64(uint1(x66)) + x62), uint64(uint1(x70))) + var x73 uint64 + var x74 uint64 + x73, x74 = bits.Add64(x57, x59, uint64(uint1(x72))) + var x75 uint64 + var x76 uint64 + x75, x76 = bits.Add64(((uint64(uint1(x58)) + uint64(uint1(x36))) + (uint64(uint1(x50)) + x38)), x60, uint64(uint1(x74))) + var x77 uint64 + var x78 uint64 + x78, x77 = bits.Mul64(x2, 0x4fffffffd) + var x79 uint64 + var x80 uint64 + x80, x79 = bits.Mul64(x2, 0xfffffffffffffffe) + var x81 uint64 + var x82 uint64 + x82, x81 = bits.Mul64(x2, 0xfffffffbffffffff) + var x83 uint64 + var x84 uint64 + x84, x83 = bits.Mul64(x2, 0x3) + var x85 uint64 + var x86 uint64 + x85, x86 = bits.Add64(x84, x81, uint64(0x0)) + var x87 uint64 + var x88 uint64 + x87, x88 = bits.Add64(x82, x79, uint64(uint1(x86))) + var x89 uint64 + var x90 uint64 + x89, x90 = bits.Add64(x80, x77, uint64(uint1(x88))) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x69, x83, uint64(0x0)) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x71, x85, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x73, x87, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x75, x89, uint64(uint1(x96))) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(x91, 0xffffffff00000001) + var x101 uint64 + var x102 uint64 + x102, x101 = bits.Mul64(x91, 0xffffffff) + var x103 uint64 + var x104 uint64 + x104, x103 = bits.Mul64(x91, 0xffffffffffffffff) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x104, x101, uint64(0x0)) + var x108 uint64 + _, x108 = bits.Add64(x91, x103, uint64(0x0)) + var x109 uint64 + var x110 uint64 + x109, x110 = bits.Add64(x93, x105, uint64(uint1(x108))) + var x111 uint64 + var x112 uint64 + x111, x112 = bits.Add64(x95, (uint64(uint1(x106)) + x102), uint64(uint1(x110))) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x97, x99, uint64(uint1(x112))) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(((uint64(uint1(x98)) + uint64(uint1(x76))) + (uint64(uint1(x90)) + x78)), x100, uint64(uint1(x114))) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x3, 0x4fffffffd) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x3, 0xfffffffffffffffe) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x3, 0xfffffffbffffffff) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x3, 0x3) + var x125 uint64 + var x126 uint64 + x125, x126 = bits.Add64(x124, x121, uint64(0x0)) + var x127 uint64 + var x128 uint64 + x127, x128 = bits.Add64(x122, x119, uint64(uint1(x126))) + var x129 uint64 + var x130 uint64 + x129, x130 = bits.Add64(x120, x117, uint64(uint1(x128))) + var x131 uint64 + var x132 uint64 + x131, x132 = bits.Add64(x109, x123, uint64(0x0)) + var x133 uint64 + var x134 uint64 + x133, x134 = bits.Add64(x111, x125, uint64(uint1(x132))) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x113, x127, uint64(uint1(x134))) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x115, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(x131, 0xffffffff00000001) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x131, 0xffffffff) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x131, 0xffffffffffffffff) + var x145 uint64 + var x146 uint64 + x145, x146 = bits.Add64(x144, x141, uint64(0x0)) + var x148 uint64 + _, x148 = bits.Add64(x131, x143, uint64(0x0)) + var x149 uint64 + var x150 uint64 + x149, x150 = bits.Add64(x133, x145, uint64(uint1(x148))) + var x151 uint64 + var x152 uint64 + x151, x152 = bits.Add64(x135, (uint64(uint1(x146)) + x142), uint64(uint1(x150))) + var x153 uint64 + var x154 uint64 + x153, x154 = bits.Add64(x137, x139, uint64(uint1(x152))) + var x155 uint64 + var x156 uint64 + x155, x156 = bits.Add64(((uint64(uint1(x138)) + uint64(uint1(x116))) + (uint64(uint1(x130)) + x118)), x140, uint64(uint1(x154))) + var x157 uint64 + var x158 uint64 + x157, x158 = bits.Sub64(x149, 0xffffffffffffffff, uint64(0x0)) + var x159 uint64 + var x160 uint64 + x159, x160 = bits.Sub64(x151, 0xffffffff, uint64(uint1(x158))) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Sub64(x153, uint64(0x0), uint64(uint1(x160))) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Sub64(x155, 0xffffffff00000001, uint64(uint1(x162))) + var x166 uint64 + _, x166 = bits.Sub64(uint64(uint1(x156)), uint64(0x0), uint64(uint1(x164))) + var x167 uint64 + cmovznzU64(&x167, uint1(x166), x157, x149) + var x168 uint64 + cmovznzU64(&x168, uint1(x166), x159, x151) + var x169 uint64 + cmovznzU64(&x169, uint1(x166), x161, x153) + var x170 uint64 + cmovznzU64(&x170, uint1(x166), x163, x155) + out1[0] = x167 + out1[1] = x168 + out1[2] = x169 + out1[3] = x170 +} + +// Nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func Nonzero(out1 *uint64, arg1 *[4]uint64) { + x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) + *out1 = x1 +} + +// Selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Selectznz(out1 *[4]uint64, arg1 uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + cmovznzU64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + cmovznzU64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + cmovznzU64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + cmovznzU64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +func ToBytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func FromBytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} + +// SetOne returns the field element one in the Montgomery domain. +// +// Postconditions: +// eval (from_montgomery out1) mod m = 1 mod m +// 0 ≤ eval out1 < m +// +func SetOne(out1 *MontgomeryDomainFieldElement) { + out1[0] = uint64(0x1) + out1[1] = 0xffffffff00000000 + out1[2] = 0xffffffffffffffff + out1[3] = 0xfffffffe +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/fq.go new file mode 100644 index 0000000000..666aeb4885 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/fq.go @@ -0,0 +1,293 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fq + +import ( + "math/big" + "sync" + + "github.com/coinbase/kryptology/pkg/core/curves/native" +) + +var p256FqInitonce sync.Once +var p256FqParams native.FieldParams + +func P256FqNew() *native.Field { + return &native.Field{ + Value: [native.FieldLimbs]uint64{}, + Params: getP256FqParams(), + Arithmetic: p256FqArithmetic{}, + } +} + +func p256FqParamsInit() { + // See FIPS 186-3, section D.2.3 + p256FqParams = native.FieldParams{ + R: [native.FieldLimbs]uint64{0x0c46353d039cdaaf, 0x4319055258e8617b, 0x0000000000000000, 0x00000000ffffffff}, + R2: [native.FieldLimbs]uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620}, + R3: [native.FieldLimbs]uint64{0xac8ebec90b65a624, 0x111f28ae0c0555c9, 0x2543b9246ba5e93f, 0x503a54e76407be65}, + Modulus: [native.FieldLimbs]uint64{0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff, 0xffffffff00000000}, + BiModulus: new(big.Int).SetBytes([]byte{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, + }), + } +} + +func getP256FqParams() *native.FieldParams { + p256FqInitonce.Do(p256FqParamsInit) + return &p256FqParams +} + +// p256FqArithmetic is a struct with all the methods needed for working +// in mod q +type p256FqArithmetic struct{} + +// ToMontgomery converts this field to montgomery form +func (f p256FqArithmetic) ToMontgomery(out, arg *[native.FieldLimbs]uint64) { + ToMontgomery((*MontgomeryDomainFieldElement)(out), (*NonMontgomeryDomainFieldElement)(arg)) +} + +// FromMontgomery converts this field from montgomery form +func (f p256FqArithmetic) FromMontgomery(out, arg *[native.FieldLimbs]uint64) { + FromMontgomery((*NonMontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Neg performs modular negation +func (f p256FqArithmetic) Neg(out, arg *[native.FieldLimbs]uint64) { + Opp((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Square performs modular square +func (f p256FqArithmetic) Square(out, arg *[native.FieldLimbs]uint64) { + Square((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg)) +} + +// Mul performs modular multiplication +func (f p256FqArithmetic) Mul(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Mul((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Add performs modular addition +func (f p256FqArithmetic) Add(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Add((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sub performs modular subtraction +func (f p256FqArithmetic) Sub(out, arg1, arg2 *[native.FieldLimbs]uint64) { + Sub((*MontgomeryDomainFieldElement)(out), (*MontgomeryDomainFieldElement)(arg1), (*MontgomeryDomainFieldElement)(arg2)) +} + +// Sqrt performs modular square root +func (f p256FqArithmetic) Sqrt(wasSquare *int, out, arg *[native.FieldLimbs]uint64) { + // See sqrt_ts_ct at + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4 + // c1 := s + // c2 := (q - 1) / (2^c1) + // c2 := [4]uint64{ + // 0x4f3b9cac2fc63255, + // 0xfbce6faada7179e8, + // 0x0fffffffffffffff, + // 0x0ffffffff0000000, + // } + // c3 := (c2 - 1) / 2 + c3 := [native.FieldLimbs]uint64{ + 0x279dce5617e3192a, + 0xfde737d56d38bcf4, + 0x07ffffffffffffff, + 0x07fffffff8000000, + } + // c4 := generator + // c5 := new(Fq).pow(generator, c2) + c5 := [native.FieldLimbs]uint64{0x1015708f7e368fe1, 0x31c6c5456ecc4511, 0x5281fe8998a19ea1, 0x0279089e10c63fe8} + var z, t, b, c, tv [native.FieldLimbs]uint64 + + native.Pow(&z, arg, &c3, getP256FqParams(), f) + Square((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&z)) + Mul((*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(arg)) + Mul((*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(arg)) + + copy(b[:], t[:]) + copy(c[:], c5[:]) + + for i := s; i >= 2; i-- { + for j := 1; j <= i-2; j++ { + Square((*MontgomeryDomainFieldElement)(&b), (*MontgomeryDomainFieldElement)(&b)) + } + // if b == 1 flag = 0 else flag = 1 + flag := -(&native.Field{ + Value: b, + Params: getP256FqParams(), + Arithmetic: f, + }).IsOne() + 1 + Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&z), (*MontgomeryDomainFieldElement)(&c)) + Selectznz(&z, uint1(flag), &z, &tv) + Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&c)) + Mul((*MontgomeryDomainFieldElement)(&tv), (*MontgomeryDomainFieldElement)(&t), (*MontgomeryDomainFieldElement)(&c)) + Selectznz(&t, uint1(flag), &t, &tv) + copy(b[:], t[:]) + } + Square((*MontgomeryDomainFieldElement)(&c), (*MontgomeryDomainFieldElement)(&z)) + *wasSquare = (&native.Field{ + Value: c, + Params: getP256FqParams(), + Arithmetic: f, + }).Equal(&native.Field{ + Value: *arg, + Params: getP256FqParams(), + Arithmetic: f, + }) + Selectznz(out, uint1(*wasSquare), out, &z) +} + +// Invert performs modular inverse +func (f p256FqArithmetic) Invert(wasInverted *int, out, arg *[native.FieldLimbs]uint64) { + // Using an addition chain from + // https://briansmith.org/ecc-inversion-addition-chains-01#p256_field_inversion + var x1, x10, x11, x101, x111, x1010, x1111, x10101, x101010, x101111 [native.FieldLimbs]uint64 + var x6, x8, x16, x32, tmp [native.FieldLimbs]uint64 + + copy(x1[:], arg[:]) + native.Pow2k(&x10, arg, 1, f) + Mul((*MontgomeryDomainFieldElement)(&x11), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x1)) + Mul((*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x11)) + Mul((*MontgomeryDomainFieldElement)(&x111), (*MontgomeryDomainFieldElement)(&x10), (*MontgomeryDomainFieldElement)(&x101)) + native.Pow2k(&x1010, &x101, 1, f) + Mul((*MontgomeryDomainFieldElement)(&x1111), (*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x1010)) + native.Pow2k(&x10101, &x1010, 1, f) + Mul((*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x1)) + native.Pow2k(&x101010, &x10101, 1, f) + Mul((*MontgomeryDomainFieldElement)(&x101111), (*MontgomeryDomainFieldElement)(&x101), (*MontgomeryDomainFieldElement)(&x101010)) + + Mul((*MontgomeryDomainFieldElement)(&x6), (*MontgomeryDomainFieldElement)(&x10101), (*MontgomeryDomainFieldElement)(&x101010)) + + native.Pow2k(&x8, &x6, 2, f) + Mul((*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x8), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&x16, &x8, 8, f) + Mul((*MontgomeryDomainFieldElement)(&x16), (*MontgomeryDomainFieldElement)(&x16), (*MontgomeryDomainFieldElement)(&x8)) + + native.Pow2k(&x32, &x16, 16, f) + Mul((*MontgomeryDomainFieldElement)(&x32), (*MontgomeryDomainFieldElement)(&x32), (*MontgomeryDomainFieldElement)(&x16)) + + native.Pow2k(&tmp, &x32, 64, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x32)) + + native.Pow2k(&tmp, &tmp, 32, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x32)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x10101)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 9, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111)) + + native.Pow2k(&tmp, &tmp, 2, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 4, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x111)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 10, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x101111)) + + native.Pow2k(&tmp, &tmp, 2, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 5, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x11)) + + native.Pow2k(&tmp, &tmp, 3, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1)) + + native.Pow2k(&tmp, &tmp, 7, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x10101)) + + native.Pow2k(&tmp, &tmp, 6, f) + Mul((*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&tmp), (*MontgomeryDomainFieldElement)(&x1111)) + + *wasInverted = (&native.Field{ + Value: *arg, + Params: getP256FqParams(), + Arithmetic: f, + }).IsNonZero() + Selectznz(out, uint1(*wasInverted), out, &tmp) +} + +// FromBytes converts a little endian byte array into a field element +func (f p256FqArithmetic) FromBytes(out *[native.FieldLimbs]uint64, arg *[native.FieldBytes]byte) { + FromBytes(out, arg) +} + +// ToBytes converts a field element to a little endian byte array +func (f p256FqArithmetic) ToBytes(out *[native.FieldBytes]byte, arg *[native.FieldLimbs]uint64) { + ToBytes(out, arg) +} + +// Selectznz performs conditional select. +// selects arg1 if choice == 0 and arg2 if choice == 1 +func (f p256FqArithmetic) Selectznz(out, arg1, arg2 *[native.FieldLimbs]uint64, choice int) { + Selectznz(out, uint1(choice), arg1, arg2) +} + +// generator = 7 mod q is a generator of the `q - 1` order multiplicative +// subgroup, or in other words a primitive element of the field. +// generator^t where t * 2^s + 1 = q +var generator = &[native.FieldLimbs]uint64{0x55eb74ab1949fac9, 0xd5af25406e5aaa5d, 0x0000000000000001, 0x00000006fffffff9} + +// s satisfies the equation 2^s * t = q - 1 with t odd. +var s = 4 + +// rootOfUnity +var rootOfUnity = &[native.FieldLimbs]uint64{0x0592d7fbb41e6602, 0x1546cad004378daf, 0xba807ace842a3dfc, 0xffc97f062a770992} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/p256_fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/p256_fq.go new file mode 100644 index 0000000000..2764963788 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq/p256_fq.go @@ -0,0 +1,1615 @@ +// Code generated by Fiat Cryptography. DO NOT EDIT. +// +// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --internal-static --package-case flatcase --public-function-case UpperCamelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case camelCase --no-prefix-fiat --doc-newline-in-typedef-bounds --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-text-before-function-name '' --doc-text-before-type-name '' --package-name fq '' 64 '2^256 - 2^224 + 2^192 - 89188191075325690597107910205041859247' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one +// +// curve description (via package name): fq +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one +// +// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "2^256 - 2^224 + 2^192 - 89188191075325690597107910205041859247") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 +package fq + +import "math/bits" + +type uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// MontgomeryDomainFieldElement is a field element in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type MontgomeryDomainFieldElement [4]uint64 + +// NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain. +// +// Bounds: +// +// [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type NonMontgomeryDomainFieldElement [4]uint64 + +// cmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func cmovznzU64(out1 *uint64, arg1 uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// Mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Mul(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffff00000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg2[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg2[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg2[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffff00000000) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg2[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg2[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg2[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg2[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffff00000000) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg2[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg2[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg2[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg2[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffff00000000) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func Square(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0xffffffff00000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0xffffffffffffffff) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0xbce6faada7179e84) + var x28 uint64 + var x29 uint64 + x29, x28 = bits.Mul64(x20, 0xf3b9cac2fc632551) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x29, x26, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x27, x24, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x25, x22, uint64(uint1(x33))) + x36 := (uint64(uint1(x35)) + x23) + var x38 uint64 + _, x38 = bits.Add64(x11, x28, uint64(0x0)) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x13, x30, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x15, x32, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64(x17, x34, uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x19, x36, uint64(uint1(x44))) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[3]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, arg1[2]) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, arg1[1]) + var x53 uint64 + var x54 uint64 + x54, x53 = bits.Mul64(x1, arg1[0]) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x54, x51, uint64(0x0)) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x52, x49, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x50, x47, uint64(uint1(x58))) + x61 := (uint64(uint1(x60)) + x48) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x39, x53, uint64(0x0)) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x41, x55, uint64(uint1(x63))) + var x66 uint64 + var x67 uint64 + x66, x67 = bits.Add64(x43, x57, uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x45, x59, uint64(uint1(x67))) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(uint64(uint1(x46)), x61, uint64(uint1(x69))) + var x72 uint64 + _, x72 = bits.Mul64(x62, 0xccd1c8aaee00bc4f) + var x74 uint64 + var x75 uint64 + x75, x74 = bits.Mul64(x72, 0xffffffff00000000) + var x76 uint64 + var x77 uint64 + x77, x76 = bits.Mul64(x72, 0xffffffffffffffff) + var x78 uint64 + var x79 uint64 + x79, x78 = bits.Mul64(x72, 0xbce6faada7179e84) + var x80 uint64 + var x81 uint64 + x81, x80 = bits.Mul64(x72, 0xf3b9cac2fc632551) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x81, x78, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x79, x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x74, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x75) + var x90 uint64 + _, x90 = bits.Add64(x62, x80, uint64(0x0)) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x64, x82, uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x66, x84, uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x68, x86, uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x70, x88, uint64(uint1(x96))) + x99 := (uint64(uint1(x98)) + uint64(uint1(x71))) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x2, arg1[3]) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(x2, arg1[2]) + var x104 uint64 + var x105 uint64 + x105, x104 = bits.Mul64(x2, arg1[1]) + var x106 uint64 + var x107 uint64 + x107, x106 = bits.Mul64(x2, arg1[0]) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x107, x104, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x105, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x103, x100, uint64(uint1(x111))) + x114 := (uint64(uint1(x113)) + x101) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x91, x106, uint64(0x0)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x93, x108, uint64(uint1(x116))) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Add64(x95, x110, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Add64(x97, x112, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Add64(x99, x114, uint64(uint1(x122))) + var x125 uint64 + _, x125 = bits.Mul64(x115, 0xccd1c8aaee00bc4f) + var x127 uint64 + var x128 uint64 + x128, x127 = bits.Mul64(x125, 0xffffffff00000000) + var x129 uint64 + var x130 uint64 + x130, x129 = bits.Mul64(x125, 0xffffffffffffffff) + var x131 uint64 + var x132 uint64 + x132, x131 = bits.Mul64(x125, 0xbce6faada7179e84) + var x133 uint64 + var x134 uint64 + x134, x133 = bits.Mul64(x125, 0xf3b9cac2fc632551) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x134, x131, uint64(0x0)) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x132, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(x130, x127, uint64(uint1(x138))) + x141 := (uint64(uint1(x140)) + x128) + var x143 uint64 + _, x143 = bits.Add64(x115, x133, uint64(0x0)) + var x144 uint64 + var x145 uint64 + x144, x145 = bits.Add64(x117, x135, uint64(uint1(x143))) + var x146 uint64 + var x147 uint64 + x146, x147 = bits.Add64(x119, x137, uint64(uint1(x145))) + var x148 uint64 + var x149 uint64 + x148, x149 = bits.Add64(x121, x139, uint64(uint1(x147))) + var x150 uint64 + var x151 uint64 + x150, x151 = bits.Add64(x123, x141, uint64(uint1(x149))) + x152 := (uint64(uint1(x151)) + uint64(uint1(x124))) + var x153 uint64 + var x154 uint64 + x154, x153 = bits.Mul64(x3, arg1[3]) + var x155 uint64 + var x156 uint64 + x156, x155 = bits.Mul64(x3, arg1[2]) + var x157 uint64 + var x158 uint64 + x158, x157 = bits.Mul64(x3, arg1[1]) + var x159 uint64 + var x160 uint64 + x160, x159 = bits.Mul64(x3, arg1[0]) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x160, x157, uint64(0x0)) + var x163 uint64 + var x164 uint64 + x163, x164 = bits.Add64(x158, x155, uint64(uint1(x162))) + var x165 uint64 + var x166 uint64 + x165, x166 = bits.Add64(x156, x153, uint64(uint1(x164))) + x167 := (uint64(uint1(x166)) + x154) + var x168 uint64 + var x169 uint64 + x168, x169 = bits.Add64(x144, x159, uint64(0x0)) + var x170 uint64 + var x171 uint64 + x170, x171 = bits.Add64(x146, x161, uint64(uint1(x169))) + var x172 uint64 + var x173 uint64 + x172, x173 = bits.Add64(x148, x163, uint64(uint1(x171))) + var x174 uint64 + var x175 uint64 + x174, x175 = bits.Add64(x150, x165, uint64(uint1(x173))) + var x176 uint64 + var x177 uint64 + x176, x177 = bits.Add64(x152, x167, uint64(uint1(x175))) + var x178 uint64 + _, x178 = bits.Mul64(x168, 0xccd1c8aaee00bc4f) + var x180 uint64 + var x181 uint64 + x181, x180 = bits.Mul64(x178, 0xffffffff00000000) + var x182 uint64 + var x183 uint64 + x183, x182 = bits.Mul64(x178, 0xffffffffffffffff) + var x184 uint64 + var x185 uint64 + x185, x184 = bits.Mul64(x178, 0xbce6faada7179e84) + var x186 uint64 + var x187 uint64 + x187, x186 = bits.Mul64(x178, 0xf3b9cac2fc632551) + var x188 uint64 + var x189 uint64 + x188, x189 = bits.Add64(x187, x184, uint64(0x0)) + var x190 uint64 + var x191 uint64 + x190, x191 = bits.Add64(x185, x182, uint64(uint1(x189))) + var x192 uint64 + var x193 uint64 + x192, x193 = bits.Add64(x183, x180, uint64(uint1(x191))) + x194 := (uint64(uint1(x193)) + x181) + var x196 uint64 + _, x196 = bits.Add64(x168, x186, uint64(0x0)) + var x197 uint64 + var x198 uint64 + x197, x198 = bits.Add64(x170, x188, uint64(uint1(x196))) + var x199 uint64 + var x200 uint64 + x199, x200 = bits.Add64(x172, x190, uint64(uint1(x198))) + var x201 uint64 + var x202 uint64 + x201, x202 = bits.Add64(x174, x192, uint64(uint1(x200))) + var x203 uint64 + var x204 uint64 + x203, x204 = bits.Add64(x176, x194, uint64(uint1(x202))) + x205 := (uint64(uint1(x204)) + uint64(uint1(x177))) + var x206 uint64 + var x207 uint64 + x206, x207 = bits.Sub64(x197, 0xf3b9cac2fc632551, uint64(0x0)) + var x208 uint64 + var x209 uint64 + x208, x209 = bits.Sub64(x199, 0xbce6faada7179e84, uint64(uint1(x207))) + var x210 uint64 + var x211 uint64 + x210, x211 = bits.Sub64(x201, 0xffffffffffffffff, uint64(uint1(x209))) + var x212 uint64 + var x213 uint64 + x212, x213 = bits.Sub64(x203, 0xffffffff00000000, uint64(uint1(x211))) + var x215 uint64 + _, x215 = bits.Sub64(x205, uint64(0x0), uint64(uint1(x213))) + var x216 uint64 + cmovznzU64(&x216, uint1(x215), x206, x197) + var x217 uint64 + cmovznzU64(&x217, uint1(x215), x208, x199) + var x218 uint64 + cmovznzU64(&x218, uint1(x215), x210, x201) + var x219 uint64 + cmovznzU64(&x219, uint1(x215), x212, x203) + out1[0] = x216 + out1[1] = x217 + out1[2] = x218 + out1[3] = x219 +} + +// Add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Add(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + var x10 uint64 + x9, x10 = bits.Sub64(x1, 0xf3b9cac2fc632551, uint64(0x0)) + var x11 uint64 + var x12 uint64 + x11, x12 = bits.Sub64(x3, 0xbce6faada7179e84, uint64(uint1(x10))) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Sub64(x5, 0xffffffffffffffff, uint64(uint1(x12))) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Sub64(x7, 0xffffffff00000000, uint64(uint1(x14))) + var x18 uint64 + _, x18 = bits.Sub64(uint64(uint1(x8)), uint64(0x0), uint64(uint1(x16))) + var x19 uint64 + cmovznzU64(&x19, uint1(x18), x9, x1) + var x20 uint64 + cmovznzU64(&x20, uint1(x18), x11, x3) + var x21 uint64 + cmovznzU64(&x21, uint1(x18), x13, x5) + var x22 uint64 + cmovznzU64(&x22, uint1(x18), x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// Sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func Sub(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement, arg2 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xf3b9cac2fc632551), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xbce6faada7179e84), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, x9, uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, (x9 & 0xffffffff00000000), uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// Opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func Opp(out1 *MontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + var x1 uint64 + var x2 uint64 + x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0)) + var x3 uint64 + var x4 uint64 + x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(uint1(x2))) + var x5 uint64 + var x6 uint64 + x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(uint1(x4))) + var x7 uint64 + var x8 uint64 + x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(uint1(x6))) + var x9 uint64 + cmovznzU64(&x9, uint1(x8), uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 uint64 + x10, x11 = bits.Add64(x1, (x9 & 0xf3b9cac2fc632551), uint64(0x0)) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x3, (x9 & 0xbce6faada7179e84), uint64(uint1(x11))) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x5, x9, uint64(uint1(x13))) + var x16 uint64 + x16, _ = bits.Add64(x7, (x9 & 0xffffffff00000000), uint64(uint1(x15))) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// FromMontgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func FromMontgomery(out1 *NonMontgomeryDomainFieldElement, arg1 *MontgomeryDomainFieldElement) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0xccd1c8aaee00bc4f) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0xffffffff00000000) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0xffffffffffffffff) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0xbce6faada7179e84) + var x10 uint64 + var x11 uint64 + x11, x10 = bits.Mul64(x2, 0xf3b9cac2fc632551) + var x12 uint64 + var x13 uint64 + x12, x13 = bits.Add64(x11, x8, uint64(0x0)) + var x14 uint64 + var x15 uint64 + x14, x15 = bits.Add64(x9, x6, uint64(uint1(x13))) + var x16 uint64 + var x17 uint64 + x16, x17 = bits.Add64(x7, x4, uint64(uint1(x15))) + var x19 uint64 + _, x19 = bits.Add64(x1, x10, uint64(0x0)) + var x20 uint64 + var x21 uint64 + x20, x21 = bits.Add64(uint64(0x0), x12, uint64(uint1(x19))) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(uint64(0x0), x14, uint64(uint1(x21))) + var x24 uint64 + var x25 uint64 + x24, x25 = bits.Add64(uint64(0x0), x16, uint64(uint1(x23))) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(x20, arg1[1], uint64(0x0)) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x22, uint64(0x0), uint64(uint1(x27))) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x24, uint64(0x0), uint64(uint1(x29))) + var x32 uint64 + _, x32 = bits.Mul64(x26, 0xccd1c8aaee00bc4f) + var x34 uint64 + var x35 uint64 + x35, x34 = bits.Mul64(x32, 0xffffffff00000000) + var x36 uint64 + var x37 uint64 + x37, x36 = bits.Mul64(x32, 0xffffffffffffffff) + var x38 uint64 + var x39 uint64 + x39, x38 = bits.Mul64(x32, 0xbce6faada7179e84) + var x40 uint64 + var x41 uint64 + x41, x40 = bits.Mul64(x32, 0xf3b9cac2fc632551) + var x42 uint64 + var x43 uint64 + x42, x43 = bits.Add64(x41, x38, uint64(0x0)) + var x44 uint64 + var x45 uint64 + x44, x45 = bits.Add64(x39, x36, uint64(uint1(x43))) + var x46 uint64 + var x47 uint64 + x46, x47 = bits.Add64(x37, x34, uint64(uint1(x45))) + var x49 uint64 + _, x49 = bits.Add64(x26, x40, uint64(0x0)) + var x50 uint64 + var x51 uint64 + x50, x51 = bits.Add64(x28, x42, uint64(uint1(x49))) + var x52 uint64 + var x53 uint64 + x52, x53 = bits.Add64(x30, x44, uint64(uint1(x51))) + var x54 uint64 + var x55 uint64 + x54, x55 = bits.Add64((uint64(uint1(x31)) + (uint64(uint1(x25)) + (uint64(uint1(x17)) + x5))), x46, uint64(uint1(x53))) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x50, arg1[2], uint64(0x0)) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x52, uint64(0x0), uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64(x54, uint64(0x0), uint64(uint1(x59))) + var x62 uint64 + _, x62 = bits.Mul64(x56, 0xccd1c8aaee00bc4f) + var x64 uint64 + var x65 uint64 + x65, x64 = bits.Mul64(x62, 0xffffffff00000000) + var x66 uint64 + var x67 uint64 + x67, x66 = bits.Mul64(x62, 0xffffffffffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x62, 0xbce6faada7179e84) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x62, 0xf3b9cac2fc632551) + var x72 uint64 + var x73 uint64 + x72, x73 = bits.Add64(x71, x68, uint64(0x0)) + var x74 uint64 + var x75 uint64 + x74, x75 = bits.Add64(x69, x66, uint64(uint1(x73))) + var x76 uint64 + var x77 uint64 + x76, x77 = bits.Add64(x67, x64, uint64(uint1(x75))) + var x79 uint64 + _, x79 = bits.Add64(x56, x70, uint64(0x0)) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x58, x72, uint64(uint1(x79))) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x60, x74, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64((uint64(uint1(x61)) + (uint64(uint1(x55)) + (uint64(uint1(x47)) + x35))), x76, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x80, arg1[3], uint64(0x0)) + var x88 uint64 + var x89 uint64 + x88, x89 = bits.Add64(x82, uint64(0x0), uint64(uint1(x87))) + var x90 uint64 + var x91 uint64 + x90, x91 = bits.Add64(x84, uint64(0x0), uint64(uint1(x89))) + var x92 uint64 + _, x92 = bits.Mul64(x86, 0xccd1c8aaee00bc4f) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x92, 0xffffffff00000000) + var x96 uint64 + var x97 uint64 + x97, x96 = bits.Mul64(x92, 0xffffffffffffffff) + var x98 uint64 + var x99 uint64 + x99, x98 = bits.Mul64(x92, 0xbce6faada7179e84) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(x92, 0xf3b9cac2fc632551) + var x102 uint64 + var x103 uint64 + x102, x103 = bits.Add64(x101, x98, uint64(0x0)) + var x104 uint64 + var x105 uint64 + x104, x105 = bits.Add64(x99, x96, uint64(uint1(x103))) + var x106 uint64 + var x107 uint64 + x106, x107 = bits.Add64(x97, x94, uint64(uint1(x105))) + var x109 uint64 + _, x109 = bits.Add64(x86, x100, uint64(0x0)) + var x110 uint64 + var x111 uint64 + x110, x111 = bits.Add64(x88, x102, uint64(uint1(x109))) + var x112 uint64 + var x113 uint64 + x112, x113 = bits.Add64(x90, x104, uint64(uint1(x111))) + var x114 uint64 + var x115 uint64 + x114, x115 = bits.Add64((uint64(uint1(x91)) + (uint64(uint1(x85)) + (uint64(uint1(x77)) + x65))), x106, uint64(uint1(x113))) + x116 := (uint64(uint1(x115)) + (uint64(uint1(x107)) + x95)) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Sub64(x110, 0xf3b9cac2fc632551, uint64(0x0)) + var x119 uint64 + var x120 uint64 + x119, x120 = bits.Sub64(x112, 0xbce6faada7179e84, uint64(uint1(x118))) + var x121 uint64 + var x122 uint64 + x121, x122 = bits.Sub64(x114, 0xffffffffffffffff, uint64(uint1(x120))) + var x123 uint64 + var x124 uint64 + x123, x124 = bits.Sub64(x116, 0xffffffff00000000, uint64(uint1(x122))) + var x126 uint64 + _, x126 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(uint1(x124))) + var x127 uint64 + cmovznzU64(&x127, uint1(x126), x117, x110) + var x128 uint64 + cmovznzU64(&x128, uint1(x126), x119, x112) + var x129 uint64 + cmovznzU64(&x129, uint1(x126), x121, x114) + var x130 uint64 + cmovznzU64(&x130, uint1(x126), x123, x116) + out1[0] = x127 + out1[1] = x128 + out1[2] = x129 + out1[3] = x130 +} + +// ToMontgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func ToMontgomery(out1 *MontgomeryDomainFieldElement, arg1 *NonMontgomeryDomainFieldElement) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x66e12d94f3d95620) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0x2845b2392b6bec59) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0x4699799c49bd6fa6) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0x83244c95be79eea2) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x12, x9, uint64(0x0)) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x10, x7, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x8, x5, uint64(uint1(x16))) + var x19 uint64 + _, x19 = bits.Mul64(x11, 0xccd1c8aaee00bc4f) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x19, 0xffffffff00000000) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x19, 0xffffffffffffffff) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(x19, 0xbce6faada7179e84) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(x19, 0xf3b9cac2fc632551) + var x29 uint64 + var x30 uint64 + x29, x30 = bits.Add64(x28, x25, uint64(0x0)) + var x31 uint64 + var x32 uint64 + x31, x32 = bits.Add64(x26, x23, uint64(uint1(x30))) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x24, x21, uint64(uint1(x32))) + var x36 uint64 + _, x36 = bits.Add64(x11, x27, uint64(0x0)) + var x37 uint64 + var x38 uint64 + x37, x38 = bits.Add64(x13, x29, uint64(uint1(x36))) + var x39 uint64 + var x40 uint64 + x39, x40 = bits.Add64(x15, x31, uint64(uint1(x38))) + var x41 uint64 + var x42 uint64 + x41, x42 = bits.Add64(x17, x33, uint64(uint1(x40))) + var x43 uint64 + var x44 uint64 + x43, x44 = bits.Add64((uint64(uint1(x18)) + x6), (uint64(uint1(x34)) + x22), uint64(uint1(x42))) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, 0x66e12d94f3d95620) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, 0x2845b2392b6bec59) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(x1, 0x4699799c49bd6fa6) + var x51 uint64 + var x52 uint64 + x52, x51 = bits.Mul64(x1, 0x83244c95be79eea2) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x52, x49, uint64(0x0)) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x50, x47, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x48, x45, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x37, x51, uint64(0x0)) + var x61 uint64 + var x62 uint64 + x61, x62 = bits.Add64(x39, x53, uint64(uint1(x60))) + var x63 uint64 + var x64 uint64 + x63, x64 = bits.Add64(x41, x55, uint64(uint1(x62))) + var x65 uint64 + var x66 uint64 + x65, x66 = bits.Add64(x43, x57, uint64(uint1(x64))) + var x67 uint64 + _, x67 = bits.Mul64(x59, 0xccd1c8aaee00bc4f) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(x67, 0xffffffff00000000) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(x67, 0xffffffffffffffff) + var x73 uint64 + var x74 uint64 + x74, x73 = bits.Mul64(x67, 0xbce6faada7179e84) + var x75 uint64 + var x76 uint64 + x76, x75 = bits.Mul64(x67, 0xf3b9cac2fc632551) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x76, x73, uint64(0x0)) + var x79 uint64 + var x80 uint64 + x79, x80 = bits.Add64(x74, x71, uint64(uint1(x78))) + var x81 uint64 + var x82 uint64 + x81, x82 = bits.Add64(x72, x69, uint64(uint1(x80))) + var x84 uint64 + _, x84 = bits.Add64(x59, x75, uint64(0x0)) + var x85 uint64 + var x86 uint64 + x85, x86 = bits.Add64(x61, x77, uint64(uint1(x84))) + var x87 uint64 + var x88 uint64 + x87, x88 = bits.Add64(x63, x79, uint64(uint1(x86))) + var x89 uint64 + var x90 uint64 + x89, x90 = bits.Add64(x65, x81, uint64(uint1(x88))) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(((uint64(uint1(x66)) + uint64(uint1(x44))) + (uint64(uint1(x58)) + x46)), (uint64(uint1(x82)) + x70), uint64(uint1(x90))) + var x93 uint64 + var x94 uint64 + x94, x93 = bits.Mul64(x2, 0x66e12d94f3d95620) + var x95 uint64 + var x96 uint64 + x96, x95 = bits.Mul64(x2, 0x2845b2392b6bec59) + var x97 uint64 + var x98 uint64 + x98, x97 = bits.Mul64(x2, 0x4699799c49bd6fa6) + var x99 uint64 + var x100 uint64 + x100, x99 = bits.Mul64(x2, 0x83244c95be79eea2) + var x101 uint64 + var x102 uint64 + x101, x102 = bits.Add64(x100, x97, uint64(0x0)) + var x103 uint64 + var x104 uint64 + x103, x104 = bits.Add64(x98, x95, uint64(uint1(x102))) + var x105 uint64 + var x106 uint64 + x105, x106 = bits.Add64(x96, x93, uint64(uint1(x104))) + var x107 uint64 + var x108 uint64 + x107, x108 = bits.Add64(x85, x99, uint64(0x0)) + var x109 uint64 + var x110 uint64 + x109, x110 = bits.Add64(x87, x101, uint64(uint1(x108))) + var x111 uint64 + var x112 uint64 + x111, x112 = bits.Add64(x89, x103, uint64(uint1(x110))) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x91, x105, uint64(uint1(x112))) + var x115 uint64 + _, x115 = bits.Mul64(x107, 0xccd1c8aaee00bc4f) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x115, 0xffffffff00000000) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x115, 0xffffffffffffffff) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x115, 0xbce6faada7179e84) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x115, 0xf3b9cac2fc632551) + var x125 uint64 + var x126 uint64 + x125, x126 = bits.Add64(x124, x121, uint64(0x0)) + var x127 uint64 + var x128 uint64 + x127, x128 = bits.Add64(x122, x119, uint64(uint1(x126))) + var x129 uint64 + var x130 uint64 + x129, x130 = bits.Add64(x120, x117, uint64(uint1(x128))) + var x132 uint64 + _, x132 = bits.Add64(x107, x123, uint64(0x0)) + var x133 uint64 + var x134 uint64 + x133, x134 = bits.Add64(x109, x125, uint64(uint1(x132))) + var x135 uint64 + var x136 uint64 + x135, x136 = bits.Add64(x111, x127, uint64(uint1(x134))) + var x137 uint64 + var x138 uint64 + x137, x138 = bits.Add64(x113, x129, uint64(uint1(x136))) + var x139 uint64 + var x140 uint64 + x139, x140 = bits.Add64(((uint64(uint1(x114)) + uint64(uint1(x92))) + (uint64(uint1(x106)) + x94)), (uint64(uint1(x130)) + x118), uint64(uint1(x138))) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, 0x66e12d94f3d95620) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x3, 0x2845b2392b6bec59) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(x3, 0x4699799c49bd6fa6) + var x147 uint64 + var x148 uint64 + x148, x147 = bits.Mul64(x3, 0x83244c95be79eea2) + var x149 uint64 + var x150 uint64 + x149, x150 = bits.Add64(x148, x145, uint64(0x0)) + var x151 uint64 + var x152 uint64 + x151, x152 = bits.Add64(x146, x143, uint64(uint1(x150))) + var x153 uint64 + var x154 uint64 + x153, x154 = bits.Add64(x144, x141, uint64(uint1(x152))) + var x155 uint64 + var x156 uint64 + x155, x156 = bits.Add64(x133, x147, uint64(0x0)) + var x157 uint64 + var x158 uint64 + x157, x158 = bits.Add64(x135, x149, uint64(uint1(x156))) + var x159 uint64 + var x160 uint64 + x159, x160 = bits.Add64(x137, x151, uint64(uint1(x158))) + var x161 uint64 + var x162 uint64 + x161, x162 = bits.Add64(x139, x153, uint64(uint1(x160))) + var x163 uint64 + _, x163 = bits.Mul64(x155, 0xccd1c8aaee00bc4f) + var x165 uint64 + var x166 uint64 + x166, x165 = bits.Mul64(x163, 0xffffffff00000000) + var x167 uint64 + var x168 uint64 + x168, x167 = bits.Mul64(x163, 0xffffffffffffffff) + var x169 uint64 + var x170 uint64 + x170, x169 = bits.Mul64(x163, 0xbce6faada7179e84) + var x171 uint64 + var x172 uint64 + x172, x171 = bits.Mul64(x163, 0xf3b9cac2fc632551) + var x173 uint64 + var x174 uint64 + x173, x174 = bits.Add64(x172, x169, uint64(0x0)) + var x175 uint64 + var x176 uint64 + x175, x176 = bits.Add64(x170, x167, uint64(uint1(x174))) + var x177 uint64 + var x178 uint64 + x177, x178 = bits.Add64(x168, x165, uint64(uint1(x176))) + var x180 uint64 + _, x180 = bits.Add64(x155, x171, uint64(0x0)) + var x181 uint64 + var x182 uint64 + x181, x182 = bits.Add64(x157, x173, uint64(uint1(x180))) + var x183 uint64 + var x184 uint64 + x183, x184 = bits.Add64(x159, x175, uint64(uint1(x182))) + var x185 uint64 + var x186 uint64 + x185, x186 = bits.Add64(x161, x177, uint64(uint1(x184))) + var x187 uint64 + var x188 uint64 + x187, x188 = bits.Add64(((uint64(uint1(x162)) + uint64(uint1(x140))) + (uint64(uint1(x154)) + x142)), (uint64(uint1(x178)) + x166), uint64(uint1(x186))) + var x189 uint64 + var x190 uint64 + x189, x190 = bits.Sub64(x181, 0xf3b9cac2fc632551, uint64(0x0)) + var x191 uint64 + var x192 uint64 + x191, x192 = bits.Sub64(x183, 0xbce6faada7179e84, uint64(uint1(x190))) + var x193 uint64 + var x194 uint64 + x193, x194 = bits.Sub64(x185, 0xffffffffffffffff, uint64(uint1(x192))) + var x195 uint64 + var x196 uint64 + x195, x196 = bits.Sub64(x187, 0xffffffff00000000, uint64(uint1(x194))) + var x198 uint64 + _, x198 = bits.Sub64(uint64(uint1(x188)), uint64(0x0), uint64(uint1(x196))) + var x199 uint64 + cmovznzU64(&x199, uint1(x198), x189, x181) + var x200 uint64 + cmovznzU64(&x200, uint1(x198), x191, x183) + var x201 uint64 + cmovznzU64(&x201, uint1(x198), x193, x185) + var x202 uint64 + cmovznzU64(&x202, uint1(x198), x195, x187) + out1[0] = x199 + out1[1] = x200 + out1[2] = x201 + out1[3] = x202 +} + +// Nonzero outputs a single non-zero word if the input is non-zero and zero otherwise. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func Nonzero(out1 *uint64, arg1 *[4]uint64) { + x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3]))) + *out1 = x1 +} + +// Selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Selectznz(out1 *[4]uint64, arg1 uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + cmovznzU64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + cmovznzU64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + cmovznzU64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + cmovznzU64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +func ToBytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func FromBytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} + +// SetOne returns the field element one in the Montgomery domain. +// +// Postconditions: +// eval (from_montgomery out1) mod m = 1 mod m +// 0 ≤ eval out1 < m +// +func SetOne(out1 *MontgomeryDomainFieldElement) { + out1[0] = 0xc46353d039cdaaf + out1[1] = 0x4319055258e8617b + out1[2] = uint64(0x0) + out1[3] = 0xffffffff +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/point.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/point.go new file mode 100644 index 0000000000..257b3a5a11 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/p256/point.go @@ -0,0 +1,317 @@ +package p256 + +import ( + "sync" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp" +) + +var ( + p256PointInitonce sync.Once + p256PointParams native.EllipticPointParams + p256PointSswuInitOnce sync.Once + p256PointSswuParams native.SswuParams +) + +func P256PointNew() *native.EllipticPoint { + return &native.EllipticPoint{ + X: fp.P256FpNew(), + Y: fp.P256FpNew(), + Z: fp.P256FpNew(), + Params: getP256PointParams(), + Arithmetic: &p256PointArithmetic{}, + } +} + +func p256PointParamsInit() { + // How these values were derived + // left for informational purposes + //params := elliptic.P256().Params() + //a := big.NewInt(-3) + //a.Mod(a, params.P) + //capA := fp.P256FpNew().SetBigInt(a) + //capB := fp.P256FpNew().SetBigInt(params.B) + //gx := fp.P256FpNew().SetBigInt(params.Gx) + //gy := fp.P256FpNew().SetBigInt(params.Gy) + + p256PointParams = native.EllipticPointParams{ + A: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xfffffffffffffffc, 0x00000003ffffffff, 0x0000000000000000, 0xfffffffc00000004}), + B: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6, 0xdc30061d04874834}), + Gx: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510, 0x18905f76a53755c6}), + Gy: fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325, 0x8571ff1825885d85}), + BitSize: 256, + Name: "P256", + } +} + +func getP256PointParams() *native.EllipticPointParams { + p256PointInitonce.Do(p256PointParamsInit) + return &p256PointParams +} + +func getP256PointSswuParams() *native.SswuParams { + p256PointSswuInitOnce.Do(p256PointSswuParamsInit) + return &p256PointSswuParams +} + +func p256PointSswuParamsInit() { + // How these values were derived + // left for informational purposes + //params := elliptic.P256().Params() + // + //// c1 = (q - 3) / 4 + //c1 := new(big.Int).Set(params.P) + //c1.Sub(c1, big.NewInt(3)) + //c1.Rsh(c1, 2) + // + //a := big.NewInt(-3) + //a.Mod(a, params.P) + //b := new(big.Int).Set(params.B) + //z := big.NewInt(-10) + //z.Mod(z, params.P) + //// sqrt(-Z^3) + //zTmp := new(big.Int).Exp(z, big.NewInt(3), nil) + //zTmp = zTmp.Neg(zTmp) + //zTmp.Mod(zTmp, params.P) + //c2 := new(big.Int).ModSqrt(zTmp, params.P) + // + //var capC1Bytes [32]byte + //c1.FillBytes(capC1Bytes[:]) + //capC1 := fp.P256FpNew().SetRaw(&[native.FieldLimbs]uint64{ + // binary.BigEndian.Uint64(capC1Bytes[24:]), + // binary.BigEndian.Uint64(capC1Bytes[16:24]), + // binary.BigEndian.Uint64(capC1Bytes[8:16]), + // binary.BigEndian.Uint64(capC1Bytes[:8]), + //}) + //capC2 := fp.P256FpNew().SetBigInt(c2) + //capA := fp.P256FpNew().SetBigInt(a) + //capB := fp.P256FpNew().SetBigInt(b) + //capZ := fp.P256FpNew().SetBigInt(z) + + p256PointSswuParams = native.SswuParams{ + C1: [native.FieldLimbs]uint64{0xffffffffffffffff, 0x000000003fffffff, 0x4000000000000000, 0x3fffffffc0000000}, + C2: [native.FieldLimbs]uint64{0x53e43951f64fdbe7, 0xb2806c63966a1a66, 0x1ac5d59c3298bf50, 0xa3323851ba997e27}, + A: [native.FieldLimbs]uint64{0xfffffffffffffffc, 0x00000003ffffffff, 0x0000000000000000, 0xfffffffc00000004}, + B: [native.FieldLimbs]uint64{0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6, 0xdc30061d04874834}, + Z: [native.FieldLimbs]uint64{0xfffffffffffffff5, 0x0000000affffffff, 0x0000000000000000, 0xfffffff50000000b}, + } +} + +type p256PointArithmetic struct{} + +func (k p256PointArithmetic) Hash(out *native.EllipticPoint, hash *native.EllipticPointHasher, msg, dst []byte) error { + var u []byte + sswuParams := getP256PointSswuParams() + + switch hash.Type() { + case native.XMD: + u = native.ExpandMsgXmd(hash, msg, dst, 96) + case native.XOF: + u = native.ExpandMsgXof(hash, msg, dst, 96) + } + var buf [64]byte + copy(buf[:48], internal.ReverseScalarBytes(u[:48])) + u0 := fp.P256FpNew().SetBytesWide(&buf) + copy(buf[:48], internal.ReverseScalarBytes(u[48:])) + u1 := fp.P256FpNew().SetBytesWide(&buf) + + q0x, q0y := sswuParams.Osswu3mod4(u0) + q1x, q1y := sswuParams.Osswu3mod4(u1) + out.X = q0x + out.Y = q0y + out.Z.SetOne() + tv := &native.EllipticPoint{ + X: q1x, + Y: q1y, + Z: fp.P256FpNew().SetOne(), + } + k.Add(out, out, tv) + return nil +} + +func (k p256PointArithmetic) Double(out, arg *native.EllipticPoint) { + // Addition formula from Renes-Costello-Batina 2015 + // (https://eprint.iacr.org/2015/1060 Algorithm 6) + var xx, yy, zz, xy2, yz2, xz2, bzz, bzz3 [native.FieldLimbs]uint64 + var yyMBzz3, yyPBzz3, yFrag, xFrag, zz3 [native.FieldLimbs]uint64 + var bxz2, bxz6, xx3Mzz3, x, y, z [native.FieldLimbs]uint64 + b := getP256PointParams().B.Value + f := arg.X.Arithmetic + + f.Square(&xx, &arg.X.Value) + f.Square(&yy, &arg.Y.Value) + f.Square(&zz, &arg.Z.Value) + + f.Mul(&xy2, &arg.X.Value, &arg.Y.Value) + f.Add(&xy2, &xy2, &xy2) + + f.Mul(&yz2, &arg.Y.Value, &arg.Z.Value) + f.Add(&yz2, &yz2, &yz2) + + f.Mul(&xz2, &arg.X.Value, &arg.Z.Value) + f.Add(&xz2, &xz2, &xz2) + + f.Mul(&bzz, &b, &zz) + f.Sub(&bzz, &bzz, &xz2) + + f.Add(&bzz3, &bzz, &bzz) + f.Add(&bzz3, &bzz3, &bzz) + + f.Sub(&yyMBzz3, &yy, &bzz3) + f.Add(&yyPBzz3, &yy, &bzz3) + f.Mul(&yFrag, &yyPBzz3, &yyMBzz3) + f.Mul(&xFrag, &yyMBzz3, &xy2) + + f.Add(&zz3, &zz, &zz) + f.Add(&zz3, &zz3, &zz) + + f.Mul(&bxz2, &b, &xz2) + f.Sub(&bxz2, &bxz2, &zz3) + f.Sub(&bxz2, &bxz2, &xx) + + f.Add(&bxz6, &bxz2, &bxz2) + f.Add(&bxz6, &bxz6, &bxz2) + + f.Add(&xx3Mzz3, &xx, &xx) + f.Add(&xx3Mzz3, &xx3Mzz3, &xx) + f.Sub(&xx3Mzz3, &xx3Mzz3, &zz3) + + f.Mul(&x, &bxz6, &yz2) + f.Sub(&x, &xFrag, &x) + + f.Mul(&y, &xx3Mzz3, &bxz6) + f.Add(&y, &yFrag, &y) + + f.Mul(&z, &yz2, &yy) + f.Add(&z, &z, &z) + f.Add(&z, &z, &z) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z +} + +func (k p256PointArithmetic) Add(out, arg1, arg2 *native.EllipticPoint) { + // Addition formula from Renes-Costello-Batina 2015 + // (https://eprint.iacr.org/2015/1060 Algorithm 4). + var xx, yy, zz, zz3, bxz, bxz3 [native.FieldLimbs]uint64 + var tv1, xyPairs, yzPairs, xzPairs [native.FieldLimbs]uint64 + var bzz, bzz3, yyMBzz3, yyPBzz3 [native.FieldLimbs]uint64 + var xx3Mzz3, x, y, z [native.FieldLimbs]uint64 + f := arg1.X.Arithmetic + b := getP256PointParams().B.Value + + f.Mul(&xx, &arg1.X.Value, &arg2.X.Value) + f.Mul(&yy, &arg1.Y.Value, &arg2.Y.Value) + f.Mul(&zz, &arg1.Z.Value, &arg2.Z.Value) + + f.Add(&tv1, &arg2.X.Value, &arg2.Y.Value) + f.Add(&xyPairs, &arg1.X.Value, &arg1.Y.Value) + f.Mul(&xyPairs, &xyPairs, &tv1) + f.Sub(&xyPairs, &xyPairs, &xx) + f.Sub(&xyPairs, &xyPairs, &yy) + + f.Add(&tv1, &arg2.Y.Value, &arg2.Z.Value) + f.Add(&yzPairs, &arg1.Y.Value, &arg1.Z.Value) + f.Mul(&yzPairs, &yzPairs, &tv1) + f.Sub(&yzPairs, &yzPairs, &yy) + f.Sub(&yzPairs, &yzPairs, &zz) + + f.Add(&tv1, &arg2.X.Value, &arg2.Z.Value) + f.Add(&xzPairs, &arg1.X.Value, &arg1.Z.Value) + f.Mul(&xzPairs, &xzPairs, &tv1) + f.Sub(&xzPairs, &xzPairs, &xx) + f.Sub(&xzPairs, &xzPairs, &zz) + + f.Mul(&bzz, &b, &zz) + f.Sub(&bzz, &xzPairs, &bzz) + + f.Add(&bzz3, &bzz, &bzz) + f.Add(&bzz3, &bzz3, &bzz) + + f.Sub(&yyMBzz3, &yy, &bzz3) + f.Add(&yyPBzz3, &yy, &bzz3) + + f.Add(&zz3, &zz, &zz) + f.Add(&zz3, &zz3, &zz) + + f.Mul(&bxz, &b, &xzPairs) + f.Sub(&bxz, &bxz, &zz3) + f.Sub(&bxz, &bxz, &xx) + + f.Add(&bxz3, &bxz, &bxz) + f.Add(&bxz3, &bxz3, &bxz) + + f.Add(&xx3Mzz3, &xx, &xx) + f.Add(&xx3Mzz3, &xx3Mzz3, &xx) + f.Sub(&xx3Mzz3, &xx3Mzz3, &zz3) + + f.Mul(&tv1, &yzPairs, &bxz3) + f.Mul(&x, &yyPBzz3, &xyPairs) + f.Sub(&x, &x, &tv1) + + f.Mul(&tv1, &xx3Mzz3, &bxz3) + f.Mul(&y, &yyPBzz3, &yyMBzz3) + f.Add(&y, &y, &tv1) + + f.Mul(&tv1, &xyPairs, &xx3Mzz3) + f.Mul(&z, &yyMBzz3, &yzPairs) + f.Add(&z, &z, &tv1) + + e1 := arg1.Z.IsZero() + e2 := arg2.Z.IsZero() + + // If arg1 is identity set it to arg2 + f.Selectznz(&z, &z, &arg2.Z.Value, e1) + f.Selectznz(&y, &y, &arg2.Y.Value, e1) + f.Selectznz(&x, &x, &arg2.X.Value, e1) + // If arg2 is identity set it to arg1 + f.Selectznz(&z, &z, &arg1.Z.Value, e2) + f.Selectznz(&y, &y, &arg1.Y.Value, e2) + f.Selectznz(&x, &x, &arg1.X.Value, e2) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z +} + +func (k p256PointArithmetic) IsOnCurve(arg *native.EllipticPoint) bool { + affine := P256PointNew() + k.ToAffine(affine, arg) + lhs := fp.P256FpNew().Square(affine.Y) + rhs := fp.P256FpNew() + k.RhsEq(rhs, affine.X) + return lhs.Equal(rhs) == 1 +} + +func (k p256PointArithmetic) ToAffine(out, arg *native.EllipticPoint) { + var wasInverted int + var zero, x, y, z [native.FieldLimbs]uint64 + f := arg.X.Arithmetic + + f.Invert(&wasInverted, &z, &arg.Z.Value) + f.Mul(&x, &arg.X.Value, &z) + f.Mul(&y, &arg.Y.Value, &z) + + out.Z.SetOne() + // If point at infinity this does nothing + f.Selectznz(&x, &zero, &x, wasInverted) + f.Selectznz(&y, &zero, &y, wasInverted) + f.Selectznz(&z, &zero, &out.Z.Value, wasInverted) + + out.X.Value = x + out.Y.Value = y + out.Z.Value = z + out.Params = arg.Params + out.Arithmetic = arg.Arithmetic +} + +func (k p256PointArithmetic) RhsEq(out, x *native.Field) { + // Elliptic curve equation for p256 is: y^2 = x^3 ax + b + out.Square(x) + out.Mul(out, x) + out.Add(out, getP256PointParams().B) + out.Add(out, fp.P256FpNew().Mul(getP256PointParams().A, x)) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/fp.go new file mode 100644 index 0000000000..659a106f04 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/fp.go @@ -0,0 +1,368 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fp + +import ( + "encoding/binary" + "fmt" + "math/big" + + "github.com/coinbase/kryptology/internal" +) + +type Fp fiat_pasta_fp_montgomery_domain_field_element + +// r = 2^256 mod p +var r = &Fp{0x34786d38fffffffd, 0x992c350be41914ad, 0xffffffffffffffff, 0x3fffffffffffffff} + +// r2 = 2^512 mod p +var r2 = &Fp{0x8c78ecb30000000f, 0xd7d30dbd8b0de0e7, 0x7797a99bc3c95d18, 0x096d41af7b9cb714} + +// r3 = 2^768 mod p +var r3 = &Fp{0xf185a5993a9e10f9, 0xf6a68f3b6ac5b1d1, 0xdf8d1014353fd42c, 0x2ae309222d2d9910} + +// generator = 5 mod p is a generator of the `p - 1` order multiplicative +// subgroup, or in other words a primitive element of the field. +var generator = &Fp{0xa1a55e68ffffffed, 0x74c2a54b4f4982f3, 0xfffffffffffffffd, 0x3fffffffffffffff} + +var s = 32 + +// modulus representation +// p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 +var modulus = &Fp{0x992d30ed00000001, 0x224698fc094cf91b, 0x0000000000000000, 0x4000000000000000} + +var biModulus = new(big.Int).SetBytes([]byte{ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x46, 0x98, 0xfc, 0x09, 0x4c, 0xf9, 0x1b, + 0x99, 0x2d, 0x30, 0xed, 0x00, 0x00, 0x00, 0x01, +}) + +// Cmp returns -1 if fp < rhs +// 0 if fp == rhs +// 1 if fp > rhs +func (fp *Fp) Cmp(rhs *Fp) int { + gt := 0 + lt := 0 + for i := len(fp) - 1; i >= 0; i-- { + gt |= int((rhs[i]-fp[i])>>63) &^ lt + lt |= int((fp[i]-rhs[i])>>63) &^ gt + } + return gt - lt +} + +// Equal returns true if fp == rhs +func (fp *Fp) Equal(rhs *Fp) bool { + t := fp[0] ^ rhs[0] + t |= fp[1] ^ rhs[1] + t |= fp[2] ^ rhs[2] + t |= fp[3] ^ rhs[3] + return t == 0 +} + +// IsZero returns true if fp == 0 +func (fp *Fp) IsZero() bool { + t := fp[0] + t |= fp[1] + t |= fp[2] + t |= fp[3] + return t == 0 +} + +// IsOne returns true if fp == R +func (fp *Fp) IsOne() bool { + return fp.Equal(r) +} + +func (fp *Fp) IsOdd() bool { + tv := new(fiat_pasta_fp_non_montgomery_domain_field_element) + fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(fp)) + return tv[0]&0x01 == 0x01 +} + +// Set fp == rhs +func (fp *Fp) Set(rhs *Fp) *Fp { + fp[0] = rhs[0] + fp[1] = rhs[1] + fp[2] = rhs[2] + fp[3] = rhs[3] + return fp +} + +// SetUint64 sets fp == rhs +func (fp *Fp) SetUint64(rhs uint64) *Fp { + r := &fiat_pasta_fp_non_montgomery_domain_field_element{rhs, 0, 0, 0} + fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), r) + return fp +} + +func (fp *Fp) SetBool(rhs bool) *Fp { + if rhs { + fp.SetOne() + } else { + fp.SetZero() + } + return fp +} + +// SetOne fp == R +func (fp *Fp) SetOne() *Fp { + return fp.Set(r) +} + +// SetZero fp == 0 +func (fp *Fp) SetZero() *Fp { + fp[0] = 0 + fp[1] = 0 + fp[2] = 0 + fp[3] = 0 + return fp +} + +// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number. +// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/fp.rs#L255 +// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits +// with the higher bits multiplied by 2^256. Thus, we perform two reductions +// +// 1. the lower bits are multiplied by R^2, as normal +// 2. the upper bits are multiplied by R^2 * 2^256 = R^3 +// +// and computing their sum in the field. It remains to see that arbitrary 256-bit +// numbers can be placed into Montgomery form safely using the reduction. The +// reduction works so long as the product is less than R=2^256 multiplied by +// the modulus. This holds because for any `c` smaller than the modulus, we have +// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the +// reduction always works so long as `c` is in the field; in this case it is either the +// constant `r2` or `r3`. +func (fp *Fp) SetBytesWide(input *[64]byte) *Fp { + d0 := fiat_pasta_fp_montgomery_domain_field_element{ + binary.LittleEndian.Uint64(input[:8]), + binary.LittleEndian.Uint64(input[8:16]), + binary.LittleEndian.Uint64(input[16:24]), + binary.LittleEndian.Uint64(input[24:32]), + } + d1 := fiat_pasta_fp_montgomery_domain_field_element{ + binary.LittleEndian.Uint64(input[32:40]), + binary.LittleEndian.Uint64(input[40:48]), + binary.LittleEndian.Uint64(input[48:56]), + binary.LittleEndian.Uint64(input[56:64]), + } + // Convert to Montgomery form + tv1 := new(fiat_pasta_fp_montgomery_domain_field_element) + tv2 := new(fiat_pasta_fp_montgomery_domain_field_element) + // d0 * r2 + d1 * r3 + fiat_pasta_fp_mul(tv1, &d0, (*fiat_pasta_fp_montgomery_domain_field_element)(r2)) + fiat_pasta_fp_mul(tv2, &d1, (*fiat_pasta_fp_montgomery_domain_field_element)(r3)) + fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), tv1, tv2) + return fp +} + +// SetBytes attempts to convert a little endian byte representation +// of a scalar into a `Fp`, failing if input is not canonical +func (fp *Fp) SetBytes(input *[32]byte) (*Fp, error) { + d0 := &Fp{ + binary.LittleEndian.Uint64(input[:8]), + binary.LittleEndian.Uint64(input[8:16]), + binary.LittleEndian.Uint64(input[16:24]), + binary.LittleEndian.Uint64(input[24:32]), + } + if d0.Cmp(modulus) != -1 { + return nil, fmt.Errorf("invalid byte sequence") + } + fiat_pasta_fp_from_bytes((*[4]uint64)(fp), input) + fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), (*fiat_pasta_fp_non_montgomery_domain_field_element)(fp)) + return fp, nil +} + +// SetBigInt initializes an element from big.Int +// The value is reduced by the modulus +func (fp *Fp) SetBigInt(bi *big.Int) *Fp { + var buffer [32]byte + r := new(big.Int).Set(bi) + r.Mod(r, biModulus) + r.FillBytes(buffer[:]) + copy(buffer[:], internal.ReverseScalarBytes(buffer[:])) + _, _ = fp.SetBytes(&buffer) + return fp +} + +// SetRaw converts a raw array into a field element +func (fp *Fp) SetRaw(array *[4]uint64) *Fp { + fiat_pasta_fp_to_montgomery((*fiat_pasta_fp_montgomery_domain_field_element)(fp), (*fiat_pasta_fp_non_montgomery_domain_field_element)(array)) + return fp +} + +// Bytes converts this element into a byte representation +// in little endian byte order +func (fp *Fp) Bytes() [32]byte { + var output [32]byte + tv := new(fiat_pasta_fp_non_montgomery_domain_field_element) + fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(fp)) + fiat_pasta_fp_to_bytes(&output, (*[4]uint64)(tv)) + return output +} + +// BigInt converts this element into the big.Int struct +func (fp *Fp) BigInt() *big.Int { + buffer := fp.Bytes() + return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:])) +} + +// Double this element +func (fp *Fp) Double(elem *Fp) *Fp { + delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem) + fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem, delem) + return fp +} + +// Square this element +func (fp *Fp) Square(elem *Fp) *Fp { + delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem) + fiat_pasta_fp_square((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem) + return fp +} + +// Sqrt this element, if it exists. If true, then value +// is a square root. If false, value is a QNR +func (fp *Fp) Sqrt(elem *Fp) (*Fp, bool) { + return fp.tonelliShanks(elem) +} + +// See sqrt_ts_ct at +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4 +func (fp *Fp) tonelliShanks(elem *Fp) (*Fp, bool) { + // c1 := 32 + // c2 := (q - 1) / (2^c1) + // c2 := [4]uint64{ + // 0x094cf91b992d30ed, + // 0x00000000224698fc, + // 0x0000000000000000, + // 0x0000000040000000, + // } + // c3 := (c2 - 1) / 2 + c3 := [4]uint64{ + 0x04a67c8dcc969876, + 0x0000000011234c7e, + 0x0000000000000000, + 0x0000000020000000, + } + // c4 := generator + // c5 := new(Fp).pow(&generator, c2) + c5 := &Fp{ + 0xa28db849bad6dbf0, + 0x9083cd03d3b539df, + 0xfba6b9ca9dc8448e, + 0x3ec928747b89c6da, + } + + z := new(Fp).pow(elem, c3) + t := new(Fp).Square(z) + t.Mul(t, elem) + + z.Mul(z, elem) + + b := new(Fp).Set(t) + c := new(Fp).Set(c5) + flags := map[bool]int{ + true: 1, + false: 0, + } + + for i := s; i >= 2; i-- { + for j := 1; j <= i-2; j++ { + b.Square(b) + } + z.CMove(z, new(Fp).Mul(z, c), flags[!b.IsOne()]) + c.Square(c) + t.CMove(t, new(Fp).Mul(t, c), flags[!b.IsOne()]) + b.Set(t) + } + wasSquare := c.Square(z).Equal(elem) + return fp.Set(z), wasSquare +} + +// Invert this element i.e. compute the multiplicative inverse +// return false, zero if this element is zero +func (fp *Fp) Invert(elem *Fp) (*Fp, bool) { + // computes elem^(p - 2) mod p + exp := [4]uint64{ + 0x992d30ecffffffff, + 0x224698fc094cf91b, + 0x0000000000000000, + 0x4000000000000000} + return fp.pow(elem, exp), !elem.IsZero() +} + +// Mul returns the result from multiplying this element by rhs +func (fp *Fp) Mul(lhs, rhs *Fp) *Fp { + dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs) + fiat_pasta_fp_mul((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs) + return fp +} + +// Sub returns the result from subtracting rhs from this element +func (fp *Fp) Sub(lhs, rhs *Fp) *Fp { + dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs) + fiat_pasta_fp_sub((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs) + return fp +} + +// Add returns the result from adding rhs to this element +func (fp *Fp) Add(lhs, rhs *Fp) *Fp { + dlhs := (*fiat_pasta_fp_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fp_montgomery_domain_field_element)(rhs) + fiat_pasta_fp_add((*fiat_pasta_fp_montgomery_domain_field_element)(fp), dlhs, drhs) + return fp +} + +// Neg returns negation of this element +func (fp *Fp) Neg(elem *Fp) *Fp { + delem := (*fiat_pasta_fp_montgomery_domain_field_element)(elem) + fiat_pasta_fp_opp((*fiat_pasta_fp_montgomery_domain_field_element)(fp), delem) + return fp +} + +// Exp exponentiates this element by exp +func (fp *Fp) Exp(base, exp *Fp) *Fp { + // convert exponent to integer form + tv := &fiat_pasta_fp_non_montgomery_domain_field_element{} + fiat_pasta_fp_from_montgomery(tv, (*fiat_pasta_fp_montgomery_domain_field_element)(exp)) + + e := (*[4]uint64)(tv) + return fp.pow(base, *e) +} + +func (fp *Fp) pow(base *Fp, exp [4]uint64) *Fp { + res := new(Fp).SetOne() + tmp := new(Fp) + + for i := len(exp) - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + res.Square(res) + tmp.Mul(res, base) + res.CMove(res, tmp, int(exp[i]>>j)&1) + } + } + return fp.Set(res) +} + +// CMove selects lhs if choice == 0 and rhs if choice == 1 +func (fp *Fp) CMove(lhs, rhs *Fp, choice int) *Fp { + dlhs := (*[4]uint64)(lhs) + drhs := (*[4]uint64)(rhs) + fiat_pasta_fp_selectznz((*[4]uint64)(fp), fiat_pasta_fp_uint1(choice), dlhs, drhs) + return fp +} + +// ToRaw converts this element into the a [4]uint64 +func (fp *Fp) ToRaw() [4]uint64 { + res := &fiat_pasta_fp_non_montgomery_domain_field_element{} + fiat_pasta_fp_from_montgomery(res, (*fiat_pasta_fp_montgomery_domain_field_element)(fp)) + return *(*[4]uint64)(res) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/pasta_fp.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/pasta_fp.go new file mode 100644 index 0000000000..5eedad1359 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp/pasta_fp.go @@ -0,0 +1,1433 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Autogenerated: './src/ExtractionOCaml/word_by_word_montgomery' --lang Go pasta_fp 64 '2^254 + 45560315531419706090280762371685220353' +// +// curve description: pasta_fp +// +// machine_wordsize = 64 (from "64") +// +// requested operations: (all) +// +// m = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 (from "2^254 + 45560315531419706090280762371685220353") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 + +package fp + +import "math/bits" + +type fiat_pasta_fp_uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type fiat_pasta_fp_int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// The type fiat_pasta_fp_montgomery_domain_field_element is a field element in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type fiat_pasta_fp_montgomery_domain_field_element [4]uint64 + +// The type fiat_pasta_fp_non_montgomery_domain_field_element is a field element NOT in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type fiat_pasta_fp_non_montgomery_domain_field_element [4]uint64 + +// The function fiat_pasta_fp_addcarryx_u64 is a thin wrapper around bits.Add64 that uses fiat_pasta_fp_uint1 rather than uint64 +func fiat_pasta_fp_addcarryx_u64(x uint64, y uint64, carry fiat_pasta_fp_uint1) (uint64, fiat_pasta_fp_uint1) { + sum, carryOut := bits.Add64(x, y, uint64(carry)) + return sum, fiat_pasta_fp_uint1(carryOut) +} + +// The function fiat_pasta_fp_subborrowx_u64 is a thin wrapper around bits.Sub64 that uses fiat_pasta_fp_uint1 rather than uint64 +func fiat_pasta_fp_subborrowx_u64(x uint64, y uint64, carry fiat_pasta_fp_uint1) (uint64, fiat_pasta_fp_uint1) { + sum, carryOut := bits.Sub64(x, y, uint64(carry)) + return sum, fiat_pasta_fp_uint1(carryOut) +} + +// The function fiat_pasta_fp_cmovznz_u64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func fiat_pasta_fp_cmovznz_u64(out1 *uint64, arg1 fiat_pasta_fp_uint1, arg2 uint64, arg3 uint64) { + x1 := arg1 + x2 := (uint64((fiat_pasta_fp_int1(0x0) - fiat_pasta_fp_int1(x1))) & 0xffffffffffffffff) + x3 := ((x2 & arg3) | ((^x2) & arg2)) + *out1 = x3 +} + +// The function fiat_pasta_fp_mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_mul(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element, arg2 *fiat_pasta_fp_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 fiat_pasta_fp_uint1 + x13, x14 = fiat_pasta_fp_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fp_uint1 + x15, x16 = fiat_pasta_fp_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fp_uint1 + x17, x18 = fiat_pasta_fp_addcarryx_u64(x8, x5, x16) + x19 := (uint64(x18) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x992d30ecffffffff) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0x4000000000000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0x224698fc094cf91b) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0x992d30ed00000001) + var x28 uint64 + var x29 fiat_pasta_fp_uint1 + x28, x29 = fiat_pasta_fp_addcarryx_u64(x27, x24, 0x0) + x30 := (uint64(x29) + x25) + var x32 fiat_pasta_fp_uint1 + _, x32 = fiat_pasta_fp_addcarryx_u64(x11, x26, 0x0) + var x33 uint64 + var x34 fiat_pasta_fp_uint1 + x33, x34 = fiat_pasta_fp_addcarryx_u64(x13, x28, x32) + var x35 uint64 + var x36 fiat_pasta_fp_uint1 + x35, x36 = fiat_pasta_fp_addcarryx_u64(x15, x30, x34) + var x37 uint64 + var x38 fiat_pasta_fp_uint1 + x37, x38 = fiat_pasta_fp_addcarryx_u64(x17, x22, x36) + var x39 uint64 + var x40 fiat_pasta_fp_uint1 + x39, x40 = fiat_pasta_fp_addcarryx_u64(x19, x23, x38) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg2[3]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg2[2]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg2[1]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[0]) + var x49 uint64 + var x50 fiat_pasta_fp_uint1 + x49, x50 = fiat_pasta_fp_addcarryx_u64(x48, x45, 0x0) + var x51 uint64 + var x52 fiat_pasta_fp_uint1 + x51, x52 = fiat_pasta_fp_addcarryx_u64(x46, x43, x50) + var x53 uint64 + var x54 fiat_pasta_fp_uint1 + x53, x54 = fiat_pasta_fp_addcarryx_u64(x44, x41, x52) + x55 := (uint64(x54) + x42) + var x56 uint64 + var x57 fiat_pasta_fp_uint1 + x56, x57 = fiat_pasta_fp_addcarryx_u64(x33, x47, 0x0) + var x58 uint64 + var x59 fiat_pasta_fp_uint1 + x58, x59 = fiat_pasta_fp_addcarryx_u64(x35, x49, x57) + var x60 uint64 + var x61 fiat_pasta_fp_uint1 + x60, x61 = fiat_pasta_fp_addcarryx_u64(x37, x51, x59) + var x62 uint64 + var x63 fiat_pasta_fp_uint1 + x62, x63 = fiat_pasta_fp_addcarryx_u64(x39, x53, x61) + var x64 uint64 + var x65 fiat_pasta_fp_uint1 + x64, x65 = fiat_pasta_fp_addcarryx_u64(uint64(x40), x55, x63) + var x66 uint64 + _, x66 = bits.Mul64(x56, 0x992d30ecffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc094cf91b) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x992d30ed00000001) + var x74 uint64 + var x75 fiat_pasta_fp_uint1 + x74, x75 = fiat_pasta_fp_addcarryx_u64(x73, x70, 0x0) + x76 := (uint64(x75) + x71) + var x78 fiat_pasta_fp_uint1 + _, x78 = fiat_pasta_fp_addcarryx_u64(x56, x72, 0x0) + var x79 uint64 + var x80 fiat_pasta_fp_uint1 + x79, x80 = fiat_pasta_fp_addcarryx_u64(x58, x74, x78) + var x81 uint64 + var x82 fiat_pasta_fp_uint1 + x81, x82 = fiat_pasta_fp_addcarryx_u64(x60, x76, x80) + var x83 uint64 + var x84 fiat_pasta_fp_uint1 + x83, x84 = fiat_pasta_fp_addcarryx_u64(x62, x68, x82) + var x85 uint64 + var x86 fiat_pasta_fp_uint1 + x85, x86 = fiat_pasta_fp_addcarryx_u64(x64, x69, x84) + x87 := (uint64(x86) + uint64(x65)) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg2[3]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg2[2]) + var x92 uint64 + var x93 uint64 + x93, x92 = bits.Mul64(x2, arg2[1]) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x2, arg2[0]) + var x96 uint64 + var x97 fiat_pasta_fp_uint1 + x96, x97 = fiat_pasta_fp_addcarryx_u64(x95, x92, 0x0) + var x98 uint64 + var x99 fiat_pasta_fp_uint1 + x98, x99 = fiat_pasta_fp_addcarryx_u64(x93, x90, x97) + var x100 uint64 + var x101 fiat_pasta_fp_uint1 + x100, x101 = fiat_pasta_fp_addcarryx_u64(x91, x88, x99) + x102 := (uint64(x101) + x89) + var x103 uint64 + var x104 fiat_pasta_fp_uint1 + x103, x104 = fiat_pasta_fp_addcarryx_u64(x79, x94, 0x0) + var x105 uint64 + var x106 fiat_pasta_fp_uint1 + x105, x106 = fiat_pasta_fp_addcarryx_u64(x81, x96, x104) + var x107 uint64 + var x108 fiat_pasta_fp_uint1 + x107, x108 = fiat_pasta_fp_addcarryx_u64(x83, x98, x106) + var x109 uint64 + var x110 fiat_pasta_fp_uint1 + x109, x110 = fiat_pasta_fp_addcarryx_u64(x85, x100, x108) + var x111 uint64 + var x112 fiat_pasta_fp_uint1 + x111, x112 = fiat_pasta_fp_addcarryx_u64(x87, x102, x110) + var x113 uint64 + _, x113 = bits.Mul64(x103, 0x992d30ecffffffff) + var x115 uint64 + var x116 uint64 + x116, x115 = bits.Mul64(x113, 0x4000000000000000) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x113, 0x224698fc094cf91b) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x113, 0x992d30ed00000001) + var x121 uint64 + var x122 fiat_pasta_fp_uint1 + x121, x122 = fiat_pasta_fp_addcarryx_u64(x120, x117, 0x0) + x123 := (uint64(x122) + x118) + var x125 fiat_pasta_fp_uint1 + _, x125 = fiat_pasta_fp_addcarryx_u64(x103, x119, 0x0) + var x126 uint64 + var x127 fiat_pasta_fp_uint1 + x126, x127 = fiat_pasta_fp_addcarryx_u64(x105, x121, x125) + var x128 uint64 + var x129 fiat_pasta_fp_uint1 + x128, x129 = fiat_pasta_fp_addcarryx_u64(x107, x123, x127) + var x130 uint64 + var x131 fiat_pasta_fp_uint1 + x130, x131 = fiat_pasta_fp_addcarryx_u64(x109, x115, x129) + var x132 uint64 + var x133 fiat_pasta_fp_uint1 + x132, x133 = fiat_pasta_fp_addcarryx_u64(x111, x116, x131) + x134 := (uint64(x133) + uint64(x112)) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg2[3]) + var x137 uint64 + var x138 uint64 + x138, x137 = bits.Mul64(x3, arg2[2]) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(x3, arg2[1]) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, arg2[0]) + var x143 uint64 + var x144 fiat_pasta_fp_uint1 + x143, x144 = fiat_pasta_fp_addcarryx_u64(x142, x139, 0x0) + var x145 uint64 + var x146 fiat_pasta_fp_uint1 + x145, x146 = fiat_pasta_fp_addcarryx_u64(x140, x137, x144) + var x147 uint64 + var x148 fiat_pasta_fp_uint1 + x147, x148 = fiat_pasta_fp_addcarryx_u64(x138, x135, x146) + x149 := (uint64(x148) + x136) + var x150 uint64 + var x151 fiat_pasta_fp_uint1 + x150, x151 = fiat_pasta_fp_addcarryx_u64(x126, x141, 0x0) + var x152 uint64 + var x153 fiat_pasta_fp_uint1 + x152, x153 = fiat_pasta_fp_addcarryx_u64(x128, x143, x151) + var x154 uint64 + var x155 fiat_pasta_fp_uint1 + x154, x155 = fiat_pasta_fp_addcarryx_u64(x130, x145, x153) + var x156 uint64 + var x157 fiat_pasta_fp_uint1 + x156, x157 = fiat_pasta_fp_addcarryx_u64(x132, x147, x155) + var x158 uint64 + var x159 fiat_pasta_fp_uint1 + x158, x159 = fiat_pasta_fp_addcarryx_u64(x134, x149, x157) + var x160 uint64 + _, x160 = bits.Mul64(x150, 0x992d30ecffffffff) + var x162 uint64 + var x163 uint64 + x163, x162 = bits.Mul64(x160, 0x4000000000000000) + var x164 uint64 + var x165 uint64 + x165, x164 = bits.Mul64(x160, 0x224698fc094cf91b) + var x166 uint64 + var x167 uint64 + x167, x166 = bits.Mul64(x160, 0x992d30ed00000001) + var x168 uint64 + var x169 fiat_pasta_fp_uint1 + x168, x169 = fiat_pasta_fp_addcarryx_u64(x167, x164, 0x0) + x170 := (uint64(x169) + x165) + var x172 fiat_pasta_fp_uint1 + _, x172 = fiat_pasta_fp_addcarryx_u64(x150, x166, 0x0) + var x173 uint64 + var x174 fiat_pasta_fp_uint1 + x173, x174 = fiat_pasta_fp_addcarryx_u64(x152, x168, x172) + var x175 uint64 + var x176 fiat_pasta_fp_uint1 + x175, x176 = fiat_pasta_fp_addcarryx_u64(x154, x170, x174) + var x177 uint64 + var x178 fiat_pasta_fp_uint1 + x177, x178 = fiat_pasta_fp_addcarryx_u64(x156, x162, x176) + var x179 uint64 + var x180 fiat_pasta_fp_uint1 + x179, x180 = fiat_pasta_fp_addcarryx_u64(x158, x163, x178) + x181 := (uint64(x180) + uint64(x159)) + var x182 uint64 + var x183 fiat_pasta_fp_uint1 + x182, x183 = fiat_pasta_fp_subborrowx_u64(x173, 0x992d30ed00000001, 0x0) + var x184 uint64 + var x185 fiat_pasta_fp_uint1 + x184, x185 = fiat_pasta_fp_subborrowx_u64(x175, 0x224698fc094cf91b, x183) + var x186 uint64 + var x187 fiat_pasta_fp_uint1 + x186, x187 = fiat_pasta_fp_subborrowx_u64(x177, uint64(0x0), x185) + var x188 uint64 + var x189 fiat_pasta_fp_uint1 + x188, x189 = fiat_pasta_fp_subborrowx_u64(x179, 0x4000000000000000, x187) + var x191 fiat_pasta_fp_uint1 + _, x191 = fiat_pasta_fp_subborrowx_u64(x181, uint64(0x0), x189) + var x192 uint64 + fiat_pasta_fp_cmovznz_u64(&x192, x191, x182, x173) + var x193 uint64 + fiat_pasta_fp_cmovznz_u64(&x193, x191, x184, x175) + var x194 uint64 + fiat_pasta_fp_cmovznz_u64(&x194, x191, x186, x177) + var x195 uint64 + fiat_pasta_fp_cmovznz_u64(&x195, x191, x188, x179) + out1[0] = x192 + out1[1] = x193 + out1[2] = x194 + out1[3] = x195 +} + +// The function fiat_pasta_fp_square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_square(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 fiat_pasta_fp_uint1 + x13, x14 = fiat_pasta_fp_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fp_uint1 + x15, x16 = fiat_pasta_fp_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fp_uint1 + x17, x18 = fiat_pasta_fp_addcarryx_u64(x8, x5, x16) + x19 := (uint64(x18) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x992d30ecffffffff) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0x4000000000000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0x224698fc094cf91b) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0x992d30ed00000001) + var x28 uint64 + var x29 fiat_pasta_fp_uint1 + x28, x29 = fiat_pasta_fp_addcarryx_u64(x27, x24, 0x0) + x30 := (uint64(x29) + x25) + var x32 fiat_pasta_fp_uint1 + _, x32 = fiat_pasta_fp_addcarryx_u64(x11, x26, 0x0) + var x33 uint64 + var x34 fiat_pasta_fp_uint1 + x33, x34 = fiat_pasta_fp_addcarryx_u64(x13, x28, x32) + var x35 uint64 + var x36 fiat_pasta_fp_uint1 + x35, x36 = fiat_pasta_fp_addcarryx_u64(x15, x30, x34) + var x37 uint64 + var x38 fiat_pasta_fp_uint1 + x37, x38 = fiat_pasta_fp_addcarryx_u64(x17, x22, x36) + var x39 uint64 + var x40 fiat_pasta_fp_uint1 + x39, x40 = fiat_pasta_fp_addcarryx_u64(x19, x23, x38) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg1[3]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg1[2]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg1[1]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[0]) + var x49 uint64 + var x50 fiat_pasta_fp_uint1 + x49, x50 = fiat_pasta_fp_addcarryx_u64(x48, x45, 0x0) + var x51 uint64 + var x52 fiat_pasta_fp_uint1 + x51, x52 = fiat_pasta_fp_addcarryx_u64(x46, x43, x50) + var x53 uint64 + var x54 fiat_pasta_fp_uint1 + x53, x54 = fiat_pasta_fp_addcarryx_u64(x44, x41, x52) + x55 := (uint64(x54) + x42) + var x56 uint64 + var x57 fiat_pasta_fp_uint1 + x56, x57 = fiat_pasta_fp_addcarryx_u64(x33, x47, 0x0) + var x58 uint64 + var x59 fiat_pasta_fp_uint1 + x58, x59 = fiat_pasta_fp_addcarryx_u64(x35, x49, x57) + var x60 uint64 + var x61 fiat_pasta_fp_uint1 + x60, x61 = fiat_pasta_fp_addcarryx_u64(x37, x51, x59) + var x62 uint64 + var x63 fiat_pasta_fp_uint1 + x62, x63 = fiat_pasta_fp_addcarryx_u64(x39, x53, x61) + var x64 uint64 + var x65 fiat_pasta_fp_uint1 + x64, x65 = fiat_pasta_fp_addcarryx_u64(uint64(x40), x55, x63) + var x66 uint64 + _, x66 = bits.Mul64(x56, 0x992d30ecffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc094cf91b) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x992d30ed00000001) + var x74 uint64 + var x75 fiat_pasta_fp_uint1 + x74, x75 = fiat_pasta_fp_addcarryx_u64(x73, x70, 0x0) + x76 := (uint64(x75) + x71) + var x78 fiat_pasta_fp_uint1 + _, x78 = fiat_pasta_fp_addcarryx_u64(x56, x72, 0x0) + var x79 uint64 + var x80 fiat_pasta_fp_uint1 + x79, x80 = fiat_pasta_fp_addcarryx_u64(x58, x74, x78) + var x81 uint64 + var x82 fiat_pasta_fp_uint1 + x81, x82 = fiat_pasta_fp_addcarryx_u64(x60, x76, x80) + var x83 uint64 + var x84 fiat_pasta_fp_uint1 + x83, x84 = fiat_pasta_fp_addcarryx_u64(x62, x68, x82) + var x85 uint64 + var x86 fiat_pasta_fp_uint1 + x85, x86 = fiat_pasta_fp_addcarryx_u64(x64, x69, x84) + x87 := (uint64(x86) + uint64(x65)) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg1[3]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg1[2]) + var x92 uint64 + var x93 uint64 + x93, x92 = bits.Mul64(x2, arg1[1]) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x2, arg1[0]) + var x96 uint64 + var x97 fiat_pasta_fp_uint1 + x96, x97 = fiat_pasta_fp_addcarryx_u64(x95, x92, 0x0) + var x98 uint64 + var x99 fiat_pasta_fp_uint1 + x98, x99 = fiat_pasta_fp_addcarryx_u64(x93, x90, x97) + var x100 uint64 + var x101 fiat_pasta_fp_uint1 + x100, x101 = fiat_pasta_fp_addcarryx_u64(x91, x88, x99) + x102 := (uint64(x101) + x89) + var x103 uint64 + var x104 fiat_pasta_fp_uint1 + x103, x104 = fiat_pasta_fp_addcarryx_u64(x79, x94, 0x0) + var x105 uint64 + var x106 fiat_pasta_fp_uint1 + x105, x106 = fiat_pasta_fp_addcarryx_u64(x81, x96, x104) + var x107 uint64 + var x108 fiat_pasta_fp_uint1 + x107, x108 = fiat_pasta_fp_addcarryx_u64(x83, x98, x106) + var x109 uint64 + var x110 fiat_pasta_fp_uint1 + x109, x110 = fiat_pasta_fp_addcarryx_u64(x85, x100, x108) + var x111 uint64 + var x112 fiat_pasta_fp_uint1 + x111, x112 = fiat_pasta_fp_addcarryx_u64(x87, x102, x110) + var x113 uint64 + _, x113 = bits.Mul64(x103, 0x992d30ecffffffff) + var x115 uint64 + var x116 uint64 + x116, x115 = bits.Mul64(x113, 0x4000000000000000) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x113, 0x224698fc094cf91b) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x113, 0x992d30ed00000001) + var x121 uint64 + var x122 fiat_pasta_fp_uint1 + x121, x122 = fiat_pasta_fp_addcarryx_u64(x120, x117, 0x0) + x123 := (uint64(x122) + x118) + var x125 fiat_pasta_fp_uint1 + _, x125 = fiat_pasta_fp_addcarryx_u64(x103, x119, 0x0) + var x126 uint64 + var x127 fiat_pasta_fp_uint1 + x126, x127 = fiat_pasta_fp_addcarryx_u64(x105, x121, x125) + var x128 uint64 + var x129 fiat_pasta_fp_uint1 + x128, x129 = fiat_pasta_fp_addcarryx_u64(x107, x123, x127) + var x130 uint64 + var x131 fiat_pasta_fp_uint1 + x130, x131 = fiat_pasta_fp_addcarryx_u64(x109, x115, x129) + var x132 uint64 + var x133 fiat_pasta_fp_uint1 + x132, x133 = fiat_pasta_fp_addcarryx_u64(x111, x116, x131) + x134 := (uint64(x133) + uint64(x112)) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg1[3]) + var x137 uint64 + var x138 uint64 + x138, x137 = bits.Mul64(x3, arg1[2]) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(x3, arg1[1]) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, arg1[0]) + var x143 uint64 + var x144 fiat_pasta_fp_uint1 + x143, x144 = fiat_pasta_fp_addcarryx_u64(x142, x139, 0x0) + var x145 uint64 + var x146 fiat_pasta_fp_uint1 + x145, x146 = fiat_pasta_fp_addcarryx_u64(x140, x137, x144) + var x147 uint64 + var x148 fiat_pasta_fp_uint1 + x147, x148 = fiat_pasta_fp_addcarryx_u64(x138, x135, x146) + x149 := (uint64(x148) + x136) + var x150 uint64 + var x151 fiat_pasta_fp_uint1 + x150, x151 = fiat_pasta_fp_addcarryx_u64(x126, x141, 0x0) + var x152 uint64 + var x153 fiat_pasta_fp_uint1 + x152, x153 = fiat_pasta_fp_addcarryx_u64(x128, x143, x151) + var x154 uint64 + var x155 fiat_pasta_fp_uint1 + x154, x155 = fiat_pasta_fp_addcarryx_u64(x130, x145, x153) + var x156 uint64 + var x157 fiat_pasta_fp_uint1 + x156, x157 = fiat_pasta_fp_addcarryx_u64(x132, x147, x155) + var x158 uint64 + var x159 fiat_pasta_fp_uint1 + x158, x159 = fiat_pasta_fp_addcarryx_u64(x134, x149, x157) + var x160 uint64 + _, x160 = bits.Mul64(x150, 0x992d30ecffffffff) + var x162 uint64 + var x163 uint64 + x163, x162 = bits.Mul64(x160, 0x4000000000000000) + var x164 uint64 + var x165 uint64 + x165, x164 = bits.Mul64(x160, 0x224698fc094cf91b) + var x166 uint64 + var x167 uint64 + x167, x166 = bits.Mul64(x160, 0x992d30ed00000001) + var x168 uint64 + var x169 fiat_pasta_fp_uint1 + x168, x169 = fiat_pasta_fp_addcarryx_u64(x167, x164, 0x0) + x170 := (uint64(x169) + x165) + var x172 fiat_pasta_fp_uint1 + _, x172 = fiat_pasta_fp_addcarryx_u64(x150, x166, 0x0) + var x173 uint64 + var x174 fiat_pasta_fp_uint1 + x173, x174 = fiat_pasta_fp_addcarryx_u64(x152, x168, x172) + var x175 uint64 + var x176 fiat_pasta_fp_uint1 + x175, x176 = fiat_pasta_fp_addcarryx_u64(x154, x170, x174) + var x177 uint64 + var x178 fiat_pasta_fp_uint1 + x177, x178 = fiat_pasta_fp_addcarryx_u64(x156, x162, x176) + var x179 uint64 + var x180 fiat_pasta_fp_uint1 + x179, x180 = fiat_pasta_fp_addcarryx_u64(x158, x163, x178) + x181 := (uint64(x180) + uint64(x159)) + var x182 uint64 + var x183 fiat_pasta_fp_uint1 + x182, x183 = fiat_pasta_fp_subborrowx_u64(x173, 0x992d30ed00000001, 0x0) + var x184 uint64 + var x185 fiat_pasta_fp_uint1 + x184, x185 = fiat_pasta_fp_subborrowx_u64(x175, 0x224698fc094cf91b, x183) + var x186 uint64 + var x187 fiat_pasta_fp_uint1 + x186, x187 = fiat_pasta_fp_subborrowx_u64(x177, uint64(0x0), x185) + var x188 uint64 + var x189 fiat_pasta_fp_uint1 + x188, x189 = fiat_pasta_fp_subborrowx_u64(x179, 0x4000000000000000, x187) + var x191 fiat_pasta_fp_uint1 + _, x191 = fiat_pasta_fp_subborrowx_u64(x181, uint64(0x0), x189) + var x192 uint64 + fiat_pasta_fp_cmovznz_u64(&x192, x191, x182, x173) + var x193 uint64 + fiat_pasta_fp_cmovznz_u64(&x193, x191, x184, x175) + var x194 uint64 + fiat_pasta_fp_cmovznz_u64(&x194, x191, x186, x177) + var x195 uint64 + fiat_pasta_fp_cmovznz_u64(&x195, x191, x188, x179) + out1[0] = x192 + out1[1] = x193 + out1[2] = x194 + out1[3] = x195 +} + +// The function fiat_pasta_fp_add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_add(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element, arg2 *fiat_pasta_fp_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fp_uint1 + x1, x2 = fiat_pasta_fp_addcarryx_u64(arg1[0], arg2[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fp_uint1 + x3, x4 = fiat_pasta_fp_addcarryx_u64(arg1[1], arg2[1], x2) + var x5 uint64 + var x6 fiat_pasta_fp_uint1 + x5, x6 = fiat_pasta_fp_addcarryx_u64(arg1[2], arg2[2], x4) + var x7 uint64 + var x8 fiat_pasta_fp_uint1 + x7, x8 = fiat_pasta_fp_addcarryx_u64(arg1[3], arg2[3], x6) + var x9 uint64 + var x10 fiat_pasta_fp_uint1 + x9, x10 = fiat_pasta_fp_subborrowx_u64(x1, 0x992d30ed00000001, 0x0) + var x11 uint64 + var x12 fiat_pasta_fp_uint1 + x11, x12 = fiat_pasta_fp_subborrowx_u64(x3, 0x224698fc094cf91b, x10) + var x13 uint64 + var x14 fiat_pasta_fp_uint1 + x13, x14 = fiat_pasta_fp_subborrowx_u64(x5, uint64(0x0), x12) + var x15 uint64 + var x16 fiat_pasta_fp_uint1 + x15, x16 = fiat_pasta_fp_subborrowx_u64(x7, 0x4000000000000000, x14) + var x18 fiat_pasta_fp_uint1 + _, x18 = fiat_pasta_fp_subborrowx_u64(uint64(x8), uint64(0x0), x16) + var x19 uint64 + fiat_pasta_fp_cmovznz_u64(&x19, x18, x9, x1) + var x20 uint64 + fiat_pasta_fp_cmovznz_u64(&x20, x18, x11, x3) + var x21 uint64 + fiat_pasta_fp_cmovznz_u64(&x21, x18, x13, x5) + var x22 uint64 + fiat_pasta_fp_cmovznz_u64(&x22, x18, x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// The function fiat_pasta_fp_sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_sub(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element, arg2 *fiat_pasta_fp_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fp_uint1 + x1, x2 = fiat_pasta_fp_subborrowx_u64(arg1[0], arg2[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fp_uint1 + x3, x4 = fiat_pasta_fp_subborrowx_u64(arg1[1], arg2[1], x2) + var x5 uint64 + var x6 fiat_pasta_fp_uint1 + x5, x6 = fiat_pasta_fp_subborrowx_u64(arg1[2], arg2[2], x4) + var x7 uint64 + var x8 fiat_pasta_fp_uint1 + x7, x8 = fiat_pasta_fp_subborrowx_u64(arg1[3], arg2[3], x6) + var x9 uint64 + fiat_pasta_fp_cmovznz_u64(&x9, x8, uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 fiat_pasta_fp_uint1 + x10, x11 = fiat_pasta_fp_addcarryx_u64(x1, (x9 & 0x992d30ed00000001), 0x0) + var x12 uint64 + var x13 fiat_pasta_fp_uint1 + x12, x13 = fiat_pasta_fp_addcarryx_u64(x3, (x9 & 0x224698fc094cf91b), x11) + var x14 uint64 + var x15 fiat_pasta_fp_uint1 + x14, x15 = fiat_pasta_fp_addcarryx_u64(x5, uint64(0x0), x13) + var x16 uint64 + x16, _ = fiat_pasta_fp_addcarryx_u64(x7, (x9 & 0x4000000000000000), x15) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// The function fiat_pasta_fp_opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_opp(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fp_uint1 + x1, x2 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), arg1[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fp_uint1 + x3, x4 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), arg1[1], x2) + var x5 uint64 + var x6 fiat_pasta_fp_uint1 + x5, x6 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), arg1[2], x4) + var x7 uint64 + var x8 fiat_pasta_fp_uint1 + x7, x8 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), arg1[3], x6) + var x9 uint64 + fiat_pasta_fp_cmovznz_u64(&x9, x8, uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 fiat_pasta_fp_uint1 + x10, x11 = fiat_pasta_fp_addcarryx_u64(x1, (x9 & 0x992d30ed00000001), 0x0) + var x12 uint64 + var x13 fiat_pasta_fp_uint1 + x12, x13 = fiat_pasta_fp_addcarryx_u64(x3, (x9 & 0x224698fc094cf91b), x11) + var x14 uint64 + var x15 fiat_pasta_fp_uint1 + x14, x15 = fiat_pasta_fp_addcarryx_u64(x5, uint64(0x0), x13) + var x16 uint64 + x16, _ = fiat_pasta_fp_addcarryx_u64(x7, (x9 & 0x4000000000000000), x15) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// The function fiat_pasta_fp_from_montgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_from_montgomery(out1 *fiat_pasta_fp_non_montgomery_domain_field_element, arg1 *fiat_pasta_fp_montgomery_domain_field_element) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0x992d30ecffffffff) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0x4000000000000000) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0x224698fc094cf91b) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0x992d30ed00000001) + var x10 uint64 + var x11 fiat_pasta_fp_uint1 + x10, x11 = fiat_pasta_fp_addcarryx_u64(x9, x6, 0x0) + var x13 fiat_pasta_fp_uint1 + _, x13 = fiat_pasta_fp_addcarryx_u64(x1, x8, 0x0) + var x14 uint64 + var x15 fiat_pasta_fp_uint1 + x14, x15 = fiat_pasta_fp_addcarryx_u64(uint64(0x0), x10, x13) + var x16 uint64 + var x17 fiat_pasta_fp_uint1 + x16, x17 = fiat_pasta_fp_addcarryx_u64(x14, arg1[1], 0x0) + var x18 uint64 + _, x18 = bits.Mul64(x16, 0x992d30ecffffffff) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(x18, 0x4000000000000000) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x18, 0x224698fc094cf91b) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x18, 0x992d30ed00000001) + var x26 uint64 + var x27 fiat_pasta_fp_uint1 + x26, x27 = fiat_pasta_fp_addcarryx_u64(x25, x22, 0x0) + var x29 fiat_pasta_fp_uint1 + _, x29 = fiat_pasta_fp_addcarryx_u64(x16, x24, 0x0) + var x30 uint64 + var x31 fiat_pasta_fp_uint1 + x30, x31 = fiat_pasta_fp_addcarryx_u64((uint64(x17) + (uint64(x15) + (uint64(x11) + x7))), x26, x29) + var x32 uint64 + var x33 fiat_pasta_fp_uint1 + x32, x33 = fiat_pasta_fp_addcarryx_u64(x4, (uint64(x27) + x23), x31) + var x34 uint64 + var x35 fiat_pasta_fp_uint1 + x34, x35 = fiat_pasta_fp_addcarryx_u64(x5, x20, x33) + var x36 uint64 + var x37 fiat_pasta_fp_uint1 + x36, x37 = fiat_pasta_fp_addcarryx_u64(x30, arg1[2], 0x0) + var x38 uint64 + var x39 fiat_pasta_fp_uint1 + x38, x39 = fiat_pasta_fp_addcarryx_u64(x32, uint64(0x0), x37) + var x40 uint64 + var x41 fiat_pasta_fp_uint1 + x40, x41 = fiat_pasta_fp_addcarryx_u64(x34, uint64(0x0), x39) + var x42 uint64 + _, x42 = bits.Mul64(x36, 0x992d30ecffffffff) + var x44 uint64 + var x45 uint64 + x45, x44 = bits.Mul64(x42, 0x4000000000000000) + var x46 uint64 + var x47 uint64 + x47, x46 = bits.Mul64(x42, 0x224698fc094cf91b) + var x48 uint64 + var x49 uint64 + x49, x48 = bits.Mul64(x42, 0x992d30ed00000001) + var x50 uint64 + var x51 fiat_pasta_fp_uint1 + x50, x51 = fiat_pasta_fp_addcarryx_u64(x49, x46, 0x0) + var x53 fiat_pasta_fp_uint1 + _, x53 = fiat_pasta_fp_addcarryx_u64(x36, x48, 0x0) + var x54 uint64 + var x55 fiat_pasta_fp_uint1 + x54, x55 = fiat_pasta_fp_addcarryx_u64(x38, x50, x53) + var x56 uint64 + var x57 fiat_pasta_fp_uint1 + x56, x57 = fiat_pasta_fp_addcarryx_u64(x40, (uint64(x51) + x47), x55) + var x58 uint64 + var x59 fiat_pasta_fp_uint1 + x58, x59 = fiat_pasta_fp_addcarryx_u64((uint64(x41) + (uint64(x35) + x21)), x44, x57) + var x60 uint64 + var x61 fiat_pasta_fp_uint1 + x60, x61 = fiat_pasta_fp_addcarryx_u64(x54, arg1[3], 0x0) + var x62 uint64 + var x63 fiat_pasta_fp_uint1 + x62, x63 = fiat_pasta_fp_addcarryx_u64(x56, uint64(0x0), x61) + var x64 uint64 + var x65 fiat_pasta_fp_uint1 + x64, x65 = fiat_pasta_fp_addcarryx_u64(x58, uint64(0x0), x63) + var x66 uint64 + _, x66 = bits.Mul64(x60, 0x992d30ecffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc094cf91b) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x992d30ed00000001) + var x74 uint64 + var x75 fiat_pasta_fp_uint1 + x74, x75 = fiat_pasta_fp_addcarryx_u64(x73, x70, 0x0) + var x77 fiat_pasta_fp_uint1 + _, x77 = fiat_pasta_fp_addcarryx_u64(x60, x72, 0x0) + var x78 uint64 + var x79 fiat_pasta_fp_uint1 + x78, x79 = fiat_pasta_fp_addcarryx_u64(x62, x74, x77) + var x80 uint64 + var x81 fiat_pasta_fp_uint1 + x80, x81 = fiat_pasta_fp_addcarryx_u64(x64, (uint64(x75) + x71), x79) + var x82 uint64 + var x83 fiat_pasta_fp_uint1 + x82, x83 = fiat_pasta_fp_addcarryx_u64((uint64(x65) + (uint64(x59) + x45)), x68, x81) + x84 := (uint64(x83) + x69) + var x85 uint64 + var x86 fiat_pasta_fp_uint1 + x85, x86 = fiat_pasta_fp_subborrowx_u64(x78, 0x992d30ed00000001, 0x0) + var x87 uint64 + var x88 fiat_pasta_fp_uint1 + x87, x88 = fiat_pasta_fp_subborrowx_u64(x80, 0x224698fc094cf91b, x86) + var x89 uint64 + var x90 fiat_pasta_fp_uint1 + x89, x90 = fiat_pasta_fp_subborrowx_u64(x82, uint64(0x0), x88) + var x91 uint64 + var x92 fiat_pasta_fp_uint1 + x91, x92 = fiat_pasta_fp_subborrowx_u64(x84, 0x4000000000000000, x90) + var x94 fiat_pasta_fp_uint1 + _, x94 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), uint64(0x0), x92) + var x95 uint64 + fiat_pasta_fp_cmovznz_u64(&x95, x94, x85, x78) + var x96 uint64 + fiat_pasta_fp_cmovznz_u64(&x96, x94, x87, x80) + var x97 uint64 + fiat_pasta_fp_cmovznz_u64(&x97, x94, x89, x82) + var x98 uint64 + fiat_pasta_fp_cmovznz_u64(&x98, x94, x91, x84) + out1[0] = x95 + out1[1] = x96 + out1[2] = x97 + out1[3] = x98 +} + +// The function fiat_pasta_fp_to_montgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fp_to_montgomery(out1 *fiat_pasta_fp_montgomery_domain_field_element, arg1 *fiat_pasta_fp_non_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x96d41af7b9cb714) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0x7797a99bc3c95d18) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0xd7d30dbd8b0de0e7) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0x8c78ecb30000000f) + var x13 uint64 + var x14 fiat_pasta_fp_uint1 + x13, x14 = fiat_pasta_fp_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fp_uint1 + x15, x16 = fiat_pasta_fp_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fp_uint1 + x17, x18 = fiat_pasta_fp_addcarryx_u64(x8, x5, x16) + var x19 uint64 + _, x19 = bits.Mul64(x11, 0x992d30ecffffffff) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x19, 0x4000000000000000) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x19, 0x224698fc094cf91b) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(x19, 0x992d30ed00000001) + var x27 uint64 + var x28 fiat_pasta_fp_uint1 + x27, x28 = fiat_pasta_fp_addcarryx_u64(x26, x23, 0x0) + var x30 fiat_pasta_fp_uint1 + _, x30 = fiat_pasta_fp_addcarryx_u64(x11, x25, 0x0) + var x31 uint64 + var x32 fiat_pasta_fp_uint1 + x31, x32 = fiat_pasta_fp_addcarryx_u64(x13, x27, x30) + var x33 uint64 + var x34 fiat_pasta_fp_uint1 + x33, x34 = fiat_pasta_fp_addcarryx_u64(x15, (uint64(x28) + x24), x32) + var x35 uint64 + var x36 fiat_pasta_fp_uint1 + x35, x36 = fiat_pasta_fp_addcarryx_u64(x17, x21, x34) + var x37 uint64 + var x38 uint64 + x38, x37 = bits.Mul64(x1, 0x96d41af7b9cb714) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(x1, 0x7797a99bc3c95d18) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, 0xd7d30dbd8b0de0e7) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, 0x8c78ecb30000000f) + var x45 uint64 + var x46 fiat_pasta_fp_uint1 + x45, x46 = fiat_pasta_fp_addcarryx_u64(x44, x41, 0x0) + var x47 uint64 + var x48 fiat_pasta_fp_uint1 + x47, x48 = fiat_pasta_fp_addcarryx_u64(x42, x39, x46) + var x49 uint64 + var x50 fiat_pasta_fp_uint1 + x49, x50 = fiat_pasta_fp_addcarryx_u64(x40, x37, x48) + var x51 uint64 + var x52 fiat_pasta_fp_uint1 + x51, x52 = fiat_pasta_fp_addcarryx_u64(x31, x43, 0x0) + var x53 uint64 + var x54 fiat_pasta_fp_uint1 + x53, x54 = fiat_pasta_fp_addcarryx_u64(x33, x45, x52) + var x55 uint64 + var x56 fiat_pasta_fp_uint1 + x55, x56 = fiat_pasta_fp_addcarryx_u64(x35, x47, x54) + var x57 uint64 + var x58 fiat_pasta_fp_uint1 + x57, x58 = fiat_pasta_fp_addcarryx_u64(((uint64(x36) + (uint64(x18) + x6)) + x22), x49, x56) + var x59 uint64 + _, x59 = bits.Mul64(x51, 0x992d30ecffffffff) + var x61 uint64 + var x62 uint64 + x62, x61 = bits.Mul64(x59, 0x4000000000000000) + var x63 uint64 + var x64 uint64 + x64, x63 = bits.Mul64(x59, 0x224698fc094cf91b) + var x65 uint64 + var x66 uint64 + x66, x65 = bits.Mul64(x59, 0x992d30ed00000001) + var x67 uint64 + var x68 fiat_pasta_fp_uint1 + x67, x68 = fiat_pasta_fp_addcarryx_u64(x66, x63, 0x0) + var x70 fiat_pasta_fp_uint1 + _, x70 = fiat_pasta_fp_addcarryx_u64(x51, x65, 0x0) + var x71 uint64 + var x72 fiat_pasta_fp_uint1 + x71, x72 = fiat_pasta_fp_addcarryx_u64(x53, x67, x70) + var x73 uint64 + var x74 fiat_pasta_fp_uint1 + x73, x74 = fiat_pasta_fp_addcarryx_u64(x55, (uint64(x68) + x64), x72) + var x75 uint64 + var x76 fiat_pasta_fp_uint1 + x75, x76 = fiat_pasta_fp_addcarryx_u64(x57, x61, x74) + var x77 uint64 + var x78 uint64 + x78, x77 = bits.Mul64(x2, 0x96d41af7b9cb714) + var x79 uint64 + var x80 uint64 + x80, x79 = bits.Mul64(x2, 0x7797a99bc3c95d18) + var x81 uint64 + var x82 uint64 + x82, x81 = bits.Mul64(x2, 0xd7d30dbd8b0de0e7) + var x83 uint64 + var x84 uint64 + x84, x83 = bits.Mul64(x2, 0x8c78ecb30000000f) + var x85 uint64 + var x86 fiat_pasta_fp_uint1 + x85, x86 = fiat_pasta_fp_addcarryx_u64(x84, x81, 0x0) + var x87 uint64 + var x88 fiat_pasta_fp_uint1 + x87, x88 = fiat_pasta_fp_addcarryx_u64(x82, x79, x86) + var x89 uint64 + var x90 fiat_pasta_fp_uint1 + x89, x90 = fiat_pasta_fp_addcarryx_u64(x80, x77, x88) + var x91 uint64 + var x92 fiat_pasta_fp_uint1 + x91, x92 = fiat_pasta_fp_addcarryx_u64(x71, x83, 0x0) + var x93 uint64 + var x94 fiat_pasta_fp_uint1 + x93, x94 = fiat_pasta_fp_addcarryx_u64(x73, x85, x92) + var x95 uint64 + var x96 fiat_pasta_fp_uint1 + x95, x96 = fiat_pasta_fp_addcarryx_u64(x75, x87, x94) + var x97 uint64 + var x98 fiat_pasta_fp_uint1 + x97, x98 = fiat_pasta_fp_addcarryx_u64(((uint64(x76) + (uint64(x58) + (uint64(x50) + x38))) + x62), x89, x96) + var x99 uint64 + _, x99 = bits.Mul64(x91, 0x992d30ecffffffff) + var x101 uint64 + var x102 uint64 + x102, x101 = bits.Mul64(x99, 0x4000000000000000) + var x103 uint64 + var x104 uint64 + x104, x103 = bits.Mul64(x99, 0x224698fc094cf91b) + var x105 uint64 + var x106 uint64 + x106, x105 = bits.Mul64(x99, 0x992d30ed00000001) + var x107 uint64 + var x108 fiat_pasta_fp_uint1 + x107, x108 = fiat_pasta_fp_addcarryx_u64(x106, x103, 0x0) + var x110 fiat_pasta_fp_uint1 + _, x110 = fiat_pasta_fp_addcarryx_u64(x91, x105, 0x0) + var x111 uint64 + var x112 fiat_pasta_fp_uint1 + x111, x112 = fiat_pasta_fp_addcarryx_u64(x93, x107, x110) + var x113 uint64 + var x114 fiat_pasta_fp_uint1 + x113, x114 = fiat_pasta_fp_addcarryx_u64(x95, (uint64(x108) + x104), x112) + var x115 uint64 + var x116 fiat_pasta_fp_uint1 + x115, x116 = fiat_pasta_fp_addcarryx_u64(x97, x101, x114) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x3, 0x96d41af7b9cb714) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x3, 0x7797a99bc3c95d18) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x3, 0xd7d30dbd8b0de0e7) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x3, 0x8c78ecb30000000f) + var x125 uint64 + var x126 fiat_pasta_fp_uint1 + x125, x126 = fiat_pasta_fp_addcarryx_u64(x124, x121, 0x0) + var x127 uint64 + var x128 fiat_pasta_fp_uint1 + x127, x128 = fiat_pasta_fp_addcarryx_u64(x122, x119, x126) + var x129 uint64 + var x130 fiat_pasta_fp_uint1 + x129, x130 = fiat_pasta_fp_addcarryx_u64(x120, x117, x128) + var x131 uint64 + var x132 fiat_pasta_fp_uint1 + x131, x132 = fiat_pasta_fp_addcarryx_u64(x111, x123, 0x0) + var x133 uint64 + var x134 fiat_pasta_fp_uint1 + x133, x134 = fiat_pasta_fp_addcarryx_u64(x113, x125, x132) + var x135 uint64 + var x136 fiat_pasta_fp_uint1 + x135, x136 = fiat_pasta_fp_addcarryx_u64(x115, x127, x134) + var x137 uint64 + var x138 fiat_pasta_fp_uint1 + x137, x138 = fiat_pasta_fp_addcarryx_u64(((uint64(x116) + (uint64(x98) + (uint64(x90) + x78))) + x102), x129, x136) + var x139 uint64 + _, x139 = bits.Mul64(x131, 0x992d30ecffffffff) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x139, 0x4000000000000000) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x139, 0x224698fc094cf91b) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(x139, 0x992d30ed00000001) + var x147 uint64 + var x148 fiat_pasta_fp_uint1 + x147, x148 = fiat_pasta_fp_addcarryx_u64(x146, x143, 0x0) + var x150 fiat_pasta_fp_uint1 + _, x150 = fiat_pasta_fp_addcarryx_u64(x131, x145, 0x0) + var x151 uint64 + var x152 fiat_pasta_fp_uint1 + x151, x152 = fiat_pasta_fp_addcarryx_u64(x133, x147, x150) + var x153 uint64 + var x154 fiat_pasta_fp_uint1 + x153, x154 = fiat_pasta_fp_addcarryx_u64(x135, (uint64(x148) + x144), x152) + var x155 uint64 + var x156 fiat_pasta_fp_uint1 + x155, x156 = fiat_pasta_fp_addcarryx_u64(x137, x141, x154) + x157 := ((uint64(x156) + (uint64(x138) + (uint64(x130) + x118))) + x142) + var x158 uint64 + var x159 fiat_pasta_fp_uint1 + x158, x159 = fiat_pasta_fp_subborrowx_u64(x151, 0x992d30ed00000001, 0x0) + var x160 uint64 + var x161 fiat_pasta_fp_uint1 + x160, x161 = fiat_pasta_fp_subborrowx_u64(x153, 0x224698fc094cf91b, x159) + var x162 uint64 + var x163 fiat_pasta_fp_uint1 + x162, x163 = fiat_pasta_fp_subborrowx_u64(x155, uint64(0x0), x161) + var x164 uint64 + var x165 fiat_pasta_fp_uint1 + x164, x165 = fiat_pasta_fp_subborrowx_u64(x157, 0x4000000000000000, x163) + var x167 fiat_pasta_fp_uint1 + _, x167 = fiat_pasta_fp_subborrowx_u64(uint64(0x0), uint64(0x0), x165) + var x168 uint64 + fiat_pasta_fp_cmovznz_u64(&x168, x167, x158, x151) + var x169 uint64 + fiat_pasta_fp_cmovznz_u64(&x169, x167, x160, x153) + var x170 uint64 + fiat_pasta_fp_cmovznz_u64(&x170, x167, x162, x155) + var x171 uint64 + fiat_pasta_fp_cmovznz_u64(&x171, x167, x164, x157) + out1[0] = x168 + out1[1] = x169 + out1[2] = x170 + out1[3] = x171 +} + +// The function fiat_pasta_fp_selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func fiat_pasta_fp_selectznz(out1 *[4]uint64, arg1 fiat_pasta_fp_uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + fiat_pasta_fp_cmovznz_u64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + fiat_pasta_fp_cmovznz_u64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + fiat_pasta_fp_cmovznz_u64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + fiat_pasta_fp_cmovznz_u64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// The function fiat_pasta_fp_to_bytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x7fffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x7f]] +func fiat_pasta_fp_to_bytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// The function fiat_pasta_fp_from_bytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x7f]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x7fffffffffffffff]] +func fiat_pasta_fp_from_bytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/fq.go new file mode 100644 index 0000000000..f47881aab0 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/fq.go @@ -0,0 +1,362 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package fq + +import ( + "encoding/binary" + "fmt" + "math/big" + + "github.com/coinbase/kryptology/internal" +) + +type Fq fiat_pasta_fq_montgomery_domain_field_element + +// r = 2^256 mod p +var r = &Fq{0x5b2b3e9cfffffffd, 0x992c350be3420567, 0xffffffffffffffff, 0x3fffffffffffffff} + +// r2 = 2^512 mod p +var r2 = &Fq{0xfc9678ff0000000f, 0x67bb433d891a16e3, 0x7fae231004ccf590, 0x096d41af7ccfdaa9} + +// r3 = 2^768 mod p +var r3 = &Fq{0x008b421c249dae4c, 0xe13bda50dba41326, 0x88fececb8e15cb63, 0x07dd97a06e6792c8} + +// generator = 5 mod p is a generator of the `p - 1` order multiplicative +// subgroup, or in other words a primitive element of the field. +var generator = &Fq{0x96bc8c8cffffffed, 0x74c2a54b49f7778e, 0xfffffffffffffffd, 0x3fffffffffffffff} + +var s = 32 + +// modulus representation +// p = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 +var modulus = &Fq{0x8c46eb2100000001, 0x224698fc0994a8dd, 0x0000000000000000, 0x4000000000000000} + +var BiModulus = new(big.Int).SetBytes([]byte{ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x46, 0x98, 0xfc, 0x09, 0x94, 0xa8, 0xdd, + 0x8c, 0x46, 0xeb, 0x21, 0x00, 0x00, 0x00, 0x01, +}) + +// Cmp returns -1 if fp < rhs +// 0 if fp == rhs +// 1 if fp > rhs +func (fq *Fq) Cmp(rhs *Fq) int { + gt := 0 + lt := 0 + for i := len(fq) - 1; i >= 0; i-- { + gt |= int((rhs[i]-fq[i])>>63) &^ lt + lt |= int((fq[i]-rhs[i])>>63) &^ gt + } + return gt - lt +} + +// Equal returns true if fp == rhs +func (fq *Fq) Equal(rhs *Fq) bool { + t := fq[0] ^ rhs[0] + t |= fq[1] ^ rhs[1] + t |= fq[2] ^ rhs[2] + t |= fq[3] ^ rhs[3] + return t == 0 +} + +// IsZero returns true if fp == 0 +func (fq *Fq) IsZero() bool { + t := fq[0] + t |= fq[1] + t |= fq[2] + t |= fq[3] + return t == 0 +} + +// IsOne returns true if fp == r +func (fq *Fq) IsOne() bool { + return fq.Equal(r) +} + +// Set fp == rhs +func (fq *Fq) Set(rhs *Fq) *Fq { + fq[0] = rhs[0] + fq[1] = rhs[1] + fq[2] = rhs[2] + fq[3] = rhs[3] + return fq +} + +// SetUint64 sets fp == rhs +func (fq *Fq) SetUint64(rhs uint64) *Fq { + r := &fiat_pasta_fq_non_montgomery_domain_field_element{rhs, 0, 0, 0} + fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), r) + return fq +} + +func (fq *Fq) SetBool(rhs bool) *Fq { + if rhs { + fq.SetOne() + } else { + fq.SetZero() + } + return fq +} + +// SetOne fp == r +func (fq *Fq) SetOne() *Fq { + return fq.Set(r) +} + +// SetZero fp == 0 +func (fq *Fq) SetZero() *Fq { + fq[0] = 0 + fq[1] = 0 + fq[2] = 0 + fq[3] = 0 + return fq +} + +// SetBytesWide takes 64 bytes as input and treats them as a 512-bit number. +// Attributed to https://github.com/zcash/pasta_curves/blob/main/src/fields/fq.rs#L255 +// We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits +// with the higher bits multiplied by 2^256. Thus, we perform two reductions +// +// 1. the lower bits are multiplied by r^2, as normal +// 2. the upper bits are multiplied by r^2 * 2^256 = r^3 +// +// and computing their sum in the field. It remains to see that arbitrary 256-bit +// numbers can be placed into Montgomery form safely using the reduction. The +// reduction works so long as the product is less than r=2^256 multiplied by +// the modulus. This holds because for any `c` smaller than the modulus, we have +// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the +// reduction always works so long as `c` is in the field; in this case it is either the +// constant `r2` or `r3`. +func (fq *Fq) SetBytesWide(input *[64]byte) *Fq { + d0 := fiat_pasta_fq_montgomery_domain_field_element{ + binary.LittleEndian.Uint64(input[:8]), + binary.LittleEndian.Uint64(input[8:16]), + binary.LittleEndian.Uint64(input[16:24]), + binary.LittleEndian.Uint64(input[24:32]), + } + d1 := fiat_pasta_fq_montgomery_domain_field_element{ + binary.LittleEndian.Uint64(input[32:40]), + binary.LittleEndian.Uint64(input[40:48]), + binary.LittleEndian.Uint64(input[48:56]), + binary.LittleEndian.Uint64(input[56:64]), + } + // Convert to Montgomery form + tv1 := &fiat_pasta_fq_montgomery_domain_field_element{} + tv2 := &fiat_pasta_fq_montgomery_domain_field_element{} + // d0 * r2 + d1 * r3 + fiat_pasta_fq_mul(tv1, &d0, (*fiat_pasta_fq_montgomery_domain_field_element)(r2)) + fiat_pasta_fq_mul(tv2, &d1, (*fiat_pasta_fq_montgomery_domain_field_element)(r3)) + fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), tv1, tv2) + return fq +} + +// SetBytes attempts to convert a little endian byte representation +// of a scalar into a `Fq`, failing if input is not canonical +func (fq *Fq) SetBytes(input *[32]byte) (*Fq, error) { + d0 := &Fq{ + binary.LittleEndian.Uint64(input[:8]), + binary.LittleEndian.Uint64(input[8:16]), + binary.LittleEndian.Uint64(input[16:24]), + binary.LittleEndian.Uint64(input[24:32]), + } + if d0.Cmp(modulus) != -1 { + return nil, fmt.Errorf("invalid byte sequence") + } + fiat_pasta_fq_from_bytes((*[4]uint64)(fq), input) + fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), (*fiat_pasta_fq_non_montgomery_domain_field_element)(fq)) + return fq, nil +} + +// SetBigInt initializes an element from big.Int +// The value is reduced by the modulus +func (fq *Fq) SetBigInt(bi *big.Int) *Fq { + var buffer [32]byte + r := new(big.Int).Set(bi) + r.Mod(r, BiModulus) + r.FillBytes(buffer[:]) + copy(buffer[:], internal.ReverseScalarBytes(buffer[:])) + _, _ = fq.SetBytes(&buffer) + return fq +} + +// SetRaw converts a raw array into a field element +func (fq *Fq) SetRaw(array *[4]uint64) *Fq { + fiat_pasta_fq_to_montgomery((*fiat_pasta_fq_montgomery_domain_field_element)(fq), (*fiat_pasta_fq_non_montgomery_domain_field_element)(array)) + return fq +} + +// Bytes converts this element into a byte representation +// in little endian byte order +func (fq *Fq) Bytes() [32]byte { + var output [32]byte + tv := &fiat_pasta_fq_non_montgomery_domain_field_element{} + fiat_pasta_fq_from_montgomery(tv, (*fiat_pasta_fq_montgomery_domain_field_element)(fq)) + fiat_pasta_fq_to_bytes(&output, (*[4]uint64)(tv)) + return output +} + +// BigInt converts this element into the big.Int struct +func (fq *Fq) BigInt() *big.Int { + buffer := fq.Bytes() + return new(big.Int).SetBytes(internal.ReverseScalarBytes(buffer[:])) +} + +// Double this element +func (fq *Fq) Double(elem *Fq) *Fq { + delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem) + fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem, delem) + return fq +} + +// Square this element +func (fq *Fq) Square(elem *Fq) *Fq { + delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem) + fiat_pasta_fq_square((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem) + return fq +} + +// Sqrt this element, if it exists. If true, then value +// is a square root. If false, value is a QNR +func (fq *Fq) Sqrt(elem *Fq) (*Fq, bool) { + return fq.tonelliShanks(elem) +} + +// See sqrt_ts_ct at +// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-I.4 +func (fq *Fq) tonelliShanks(elem *Fq) (*Fq, bool) { + // c1 := 32 + // c2 := (q - 1) / (2^c1) + //c2 := [4]uint64{ + // 0x0994a8dd8c46eb21, + // 0x00000000224698fc, + // 0x0000000000000000, + // 0x0000000040000000, + //} + // c3 := (c2 - 1) / 2 + c3 := [4]uint64{ + 0x04ca546ec6237590, + 0x0000000011234c7e, + 0x0000000000000000, + 0x0000000020000000, + } + //c4 := generator + //c5 := new(Fq).pow(&generator, c2) + c5 := &Fq{ + 0x218077428c9942de, + 0xcc49578921b60494, + 0xac2e5d27b2efbee2, + 0xb79fa897f2db056, + } + + z := new(Fq).pow(elem, c3) + t := new(Fq).Square(z) + t.Mul(t, elem) + + z.Mul(z, elem) + + b := new(Fq).Set(t) + c := new(Fq).Set(c5) + flags := map[bool]int{ + true: 1, + false: 0, + } + + for i := s; i >= 2; i-- { + for j := 1; j <= i-2; j++ { + b.Square(b) + } + z.CMove(z, new(Fq).Mul(z, c), flags[!b.IsOne()]) + c.Square(c) + t.CMove(t, new(Fq).Mul(t, c), flags[!b.IsOne()]) + b.Set(t) + } + wasSquare := c.Square(z).Equal(elem) + return fq.Set(z), wasSquare +} + +// Invert this element i.e. compute the multiplicative inverse +// return false, zero if this element is zero +func (fq *Fq) Invert(elem *Fq) (*Fq, bool) { + // computes elem^(p - 2) mod p + exp := [4]uint64{ + 0x8c46eb20ffffffff, + 0x224698fc0994a8dd, + 0x0000000000000000, + 0x4000000000000000} + return fq.pow(elem, exp), !elem.IsZero() +} + +// Mul returns the result from multiplying this element by rhs +func (fq *Fq) Mul(lhs, rhs *Fq) *Fq { + dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs) + fiat_pasta_fq_mul((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs) + return fq +} + +// Sub returns the result from subtracting rhs from this element +func (fq *Fq) Sub(lhs, rhs *Fq) *Fq { + dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs) + fiat_pasta_fq_sub((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs) + return fq +} + +// Add returns the result from adding rhs to this element +func (fq *Fq) Add(lhs, rhs *Fq) *Fq { + dlhs := (*fiat_pasta_fq_montgomery_domain_field_element)(lhs) + drhs := (*fiat_pasta_fq_montgomery_domain_field_element)(rhs) + fiat_pasta_fq_add((*fiat_pasta_fq_montgomery_domain_field_element)(fq), dlhs, drhs) + return fq +} + +// Neg returns negation of this element +func (fq *Fq) Neg(elem *Fq) *Fq { + delem := (*fiat_pasta_fq_montgomery_domain_field_element)(elem) + fiat_pasta_fq_opp((*fiat_pasta_fq_montgomery_domain_field_element)(fq), delem) + return fq +} + +// Exp exponentiates this element by exp +func (fq *Fq) Exp(base, exp *Fq) *Fq { + // convert exponent to integer form + tv := &fiat_pasta_fq_non_montgomery_domain_field_element{} + fiat_pasta_fq_from_montgomery(tv, (*fiat_pasta_fq_montgomery_domain_field_element)(exp)) + + e := (*[4]uint64)(tv) + return fq.pow(base, *e) +} + +func (fq *Fq) pow(base *Fq, exp [4]uint64) *Fq { + res := new(Fq).SetOne() + tmp := new(Fq) + + for i := len(exp) - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + res.Square(res) + tmp.Mul(res, base) + res.CMove(res, tmp, int(exp[i]>>j)&1) + } + } + return fq.Set(res) +} + +// CMove selects lhs if choice == 0 and rhs if choice == 1 +func (fq *Fq) CMove(lhs, rhs *Fq, choice int) *Fq { + dlhs := (*[4]uint64)(lhs) + drhs := (*[4]uint64)(rhs) + fiat_pasta_fq_selectznz((*[4]uint64)(fq), fiat_pasta_fq_uint1(choice), dlhs, drhs) + return fq +} + +// ToRaw converts this element into the a [4]uint64 +func (fq *Fq) ToRaw() [4]uint64 { + res := &fiat_pasta_fq_non_montgomery_domain_field_element{} + fiat_pasta_fq_from_montgomery(res, (*fiat_pasta_fq_montgomery_domain_field_element)(fq)) + return *(*[4]uint64)(res) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/pasta_fq.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/pasta_fq.go new file mode 100644 index 0000000000..85ad0284c8 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq/pasta_fq.go @@ -0,0 +1,1433 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Autogenerated: './src/ExtractionOCaml/word_by_word_montgomery' --lang Go pasta_fq 64 '2^254 + 45560315531506369815346746415080538113' +// +// curve description: pasta_fq +// +// machine_wordsize = 64 (from "64") +// +// requested operations: (all) +// +// m = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 (from "2^254 + 45560315531506369815346746415080538113") +// +// +// +// NOTE: In addition to the bounds specified above each function, all +// +// functions synthesized for this Montgomery arithmetic require the +// +// input to be strictly less than the prime modulus (m), and also +// +// require the input to be in the unique saturated representation. +// +// All functions also ensure that these two properties are true of +// +// return values. +// +// +// +// Computed values: +// +// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) +// +// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) +// +// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in +// +// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256 + +package fq + +import "math/bits" + +type fiat_pasta_fq_uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type fiat_pasta_fq_int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// The type fiat_pasta_fq_montgomery_domain_field_element is a field element in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type fiat_pasta_fq_montgomery_domain_field_element [4]uint64 + +// The type fiat_pasta_fq_non_montgomery_domain_field_element is a field element NOT in the Montgomery domain. +// +// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +type fiat_pasta_fq_non_montgomery_domain_field_element [4]uint64 + +// The function fiat_pasta_fq_addcarryx_u64 is a thin wrapper around bits.Add64 that uses fiat_pasta_fq_uint1 rather than uint64 +func fiat_pasta_fq_addcarryx_u64(x uint64, y uint64, carry fiat_pasta_fq_uint1) (uint64, fiat_pasta_fq_uint1) { + sum, carryOut := bits.Add64(x, y, uint64(carry)) + return sum, fiat_pasta_fq_uint1(carryOut) +} + +// The function fiat_pasta_fq_subborrowx_u64 is a thin wrapper around bits.Sub64 that uses fiat_pasta_fq_uint1 rather than uint64 +func fiat_pasta_fq_subborrowx_u64(x uint64, y uint64, carry fiat_pasta_fq_uint1) (uint64, fiat_pasta_fq_uint1) { + sum, carryOut := bits.Sub64(x, y, uint64(carry)) + return sum, fiat_pasta_fq_uint1(carryOut) +} + +// The function fiat_pasta_fq_cmovznz_u64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func fiat_pasta_fq_cmovznz_u64(out1 *uint64, arg1 fiat_pasta_fq_uint1, arg2 uint64, arg3 uint64) { + x1 := arg1 + x2 := (uint64((fiat_pasta_fq_int1(0x0) - fiat_pasta_fq_int1(x1))) & 0xffffffffffffffff) + x3 := ((x2 & arg3) | ((^x2) & arg2)) + *out1 = x3 +} + +// The function fiat_pasta_fq_mul multiplies two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_mul(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element, arg2 *fiat_pasta_fq_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg2[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg2[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg2[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg2[0]) + var x13 uint64 + var x14 fiat_pasta_fq_uint1 + x13, x14 = fiat_pasta_fq_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fq_uint1 + x15, x16 = fiat_pasta_fq_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fq_uint1 + x17, x18 = fiat_pasta_fq_addcarryx_u64(x8, x5, x16) + x19 := (uint64(x18) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x8c46eb20ffffffff) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0x4000000000000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0x224698fc0994a8dd) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0x8c46eb2100000001) + var x28 uint64 + var x29 fiat_pasta_fq_uint1 + x28, x29 = fiat_pasta_fq_addcarryx_u64(x27, x24, 0x0) + x30 := (uint64(x29) + x25) + var x32 fiat_pasta_fq_uint1 + _, x32 = fiat_pasta_fq_addcarryx_u64(x11, x26, 0x0) + var x33 uint64 + var x34 fiat_pasta_fq_uint1 + x33, x34 = fiat_pasta_fq_addcarryx_u64(x13, x28, x32) + var x35 uint64 + var x36 fiat_pasta_fq_uint1 + x35, x36 = fiat_pasta_fq_addcarryx_u64(x15, x30, x34) + var x37 uint64 + var x38 fiat_pasta_fq_uint1 + x37, x38 = fiat_pasta_fq_addcarryx_u64(x17, x22, x36) + var x39 uint64 + var x40 fiat_pasta_fq_uint1 + x39, x40 = fiat_pasta_fq_addcarryx_u64(x19, x23, x38) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg2[3]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg2[2]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg2[1]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg2[0]) + var x49 uint64 + var x50 fiat_pasta_fq_uint1 + x49, x50 = fiat_pasta_fq_addcarryx_u64(x48, x45, 0x0) + var x51 uint64 + var x52 fiat_pasta_fq_uint1 + x51, x52 = fiat_pasta_fq_addcarryx_u64(x46, x43, x50) + var x53 uint64 + var x54 fiat_pasta_fq_uint1 + x53, x54 = fiat_pasta_fq_addcarryx_u64(x44, x41, x52) + x55 := (uint64(x54) + x42) + var x56 uint64 + var x57 fiat_pasta_fq_uint1 + x56, x57 = fiat_pasta_fq_addcarryx_u64(x33, x47, 0x0) + var x58 uint64 + var x59 fiat_pasta_fq_uint1 + x58, x59 = fiat_pasta_fq_addcarryx_u64(x35, x49, x57) + var x60 uint64 + var x61 fiat_pasta_fq_uint1 + x60, x61 = fiat_pasta_fq_addcarryx_u64(x37, x51, x59) + var x62 uint64 + var x63 fiat_pasta_fq_uint1 + x62, x63 = fiat_pasta_fq_addcarryx_u64(x39, x53, x61) + var x64 uint64 + var x65 fiat_pasta_fq_uint1 + x64, x65 = fiat_pasta_fq_addcarryx_u64(uint64(x40), x55, x63) + var x66 uint64 + _, x66 = bits.Mul64(x56, 0x8c46eb20ffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc0994a8dd) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x8c46eb2100000001) + var x74 uint64 + var x75 fiat_pasta_fq_uint1 + x74, x75 = fiat_pasta_fq_addcarryx_u64(x73, x70, 0x0) + x76 := (uint64(x75) + x71) + var x78 fiat_pasta_fq_uint1 + _, x78 = fiat_pasta_fq_addcarryx_u64(x56, x72, 0x0) + var x79 uint64 + var x80 fiat_pasta_fq_uint1 + x79, x80 = fiat_pasta_fq_addcarryx_u64(x58, x74, x78) + var x81 uint64 + var x82 fiat_pasta_fq_uint1 + x81, x82 = fiat_pasta_fq_addcarryx_u64(x60, x76, x80) + var x83 uint64 + var x84 fiat_pasta_fq_uint1 + x83, x84 = fiat_pasta_fq_addcarryx_u64(x62, x68, x82) + var x85 uint64 + var x86 fiat_pasta_fq_uint1 + x85, x86 = fiat_pasta_fq_addcarryx_u64(x64, x69, x84) + x87 := (uint64(x86) + uint64(x65)) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg2[3]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg2[2]) + var x92 uint64 + var x93 uint64 + x93, x92 = bits.Mul64(x2, arg2[1]) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x2, arg2[0]) + var x96 uint64 + var x97 fiat_pasta_fq_uint1 + x96, x97 = fiat_pasta_fq_addcarryx_u64(x95, x92, 0x0) + var x98 uint64 + var x99 fiat_pasta_fq_uint1 + x98, x99 = fiat_pasta_fq_addcarryx_u64(x93, x90, x97) + var x100 uint64 + var x101 fiat_pasta_fq_uint1 + x100, x101 = fiat_pasta_fq_addcarryx_u64(x91, x88, x99) + x102 := (uint64(x101) + x89) + var x103 uint64 + var x104 fiat_pasta_fq_uint1 + x103, x104 = fiat_pasta_fq_addcarryx_u64(x79, x94, 0x0) + var x105 uint64 + var x106 fiat_pasta_fq_uint1 + x105, x106 = fiat_pasta_fq_addcarryx_u64(x81, x96, x104) + var x107 uint64 + var x108 fiat_pasta_fq_uint1 + x107, x108 = fiat_pasta_fq_addcarryx_u64(x83, x98, x106) + var x109 uint64 + var x110 fiat_pasta_fq_uint1 + x109, x110 = fiat_pasta_fq_addcarryx_u64(x85, x100, x108) + var x111 uint64 + var x112 fiat_pasta_fq_uint1 + x111, x112 = fiat_pasta_fq_addcarryx_u64(x87, x102, x110) + var x113 uint64 + _, x113 = bits.Mul64(x103, 0x8c46eb20ffffffff) + var x115 uint64 + var x116 uint64 + x116, x115 = bits.Mul64(x113, 0x4000000000000000) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x113, 0x224698fc0994a8dd) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x113, 0x8c46eb2100000001) + var x121 uint64 + var x122 fiat_pasta_fq_uint1 + x121, x122 = fiat_pasta_fq_addcarryx_u64(x120, x117, 0x0) + x123 := (uint64(x122) + x118) + var x125 fiat_pasta_fq_uint1 + _, x125 = fiat_pasta_fq_addcarryx_u64(x103, x119, 0x0) + var x126 uint64 + var x127 fiat_pasta_fq_uint1 + x126, x127 = fiat_pasta_fq_addcarryx_u64(x105, x121, x125) + var x128 uint64 + var x129 fiat_pasta_fq_uint1 + x128, x129 = fiat_pasta_fq_addcarryx_u64(x107, x123, x127) + var x130 uint64 + var x131 fiat_pasta_fq_uint1 + x130, x131 = fiat_pasta_fq_addcarryx_u64(x109, x115, x129) + var x132 uint64 + var x133 fiat_pasta_fq_uint1 + x132, x133 = fiat_pasta_fq_addcarryx_u64(x111, x116, x131) + x134 := (uint64(x133) + uint64(x112)) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg2[3]) + var x137 uint64 + var x138 uint64 + x138, x137 = bits.Mul64(x3, arg2[2]) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(x3, arg2[1]) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, arg2[0]) + var x143 uint64 + var x144 fiat_pasta_fq_uint1 + x143, x144 = fiat_pasta_fq_addcarryx_u64(x142, x139, 0x0) + var x145 uint64 + var x146 fiat_pasta_fq_uint1 + x145, x146 = fiat_pasta_fq_addcarryx_u64(x140, x137, x144) + var x147 uint64 + var x148 fiat_pasta_fq_uint1 + x147, x148 = fiat_pasta_fq_addcarryx_u64(x138, x135, x146) + x149 := (uint64(x148) + x136) + var x150 uint64 + var x151 fiat_pasta_fq_uint1 + x150, x151 = fiat_pasta_fq_addcarryx_u64(x126, x141, 0x0) + var x152 uint64 + var x153 fiat_pasta_fq_uint1 + x152, x153 = fiat_pasta_fq_addcarryx_u64(x128, x143, x151) + var x154 uint64 + var x155 fiat_pasta_fq_uint1 + x154, x155 = fiat_pasta_fq_addcarryx_u64(x130, x145, x153) + var x156 uint64 + var x157 fiat_pasta_fq_uint1 + x156, x157 = fiat_pasta_fq_addcarryx_u64(x132, x147, x155) + var x158 uint64 + var x159 fiat_pasta_fq_uint1 + x158, x159 = fiat_pasta_fq_addcarryx_u64(x134, x149, x157) + var x160 uint64 + _, x160 = bits.Mul64(x150, 0x8c46eb20ffffffff) + var x162 uint64 + var x163 uint64 + x163, x162 = bits.Mul64(x160, 0x4000000000000000) + var x164 uint64 + var x165 uint64 + x165, x164 = bits.Mul64(x160, 0x224698fc0994a8dd) + var x166 uint64 + var x167 uint64 + x167, x166 = bits.Mul64(x160, 0x8c46eb2100000001) + var x168 uint64 + var x169 fiat_pasta_fq_uint1 + x168, x169 = fiat_pasta_fq_addcarryx_u64(x167, x164, 0x0) + x170 := (uint64(x169) + x165) + var x172 fiat_pasta_fq_uint1 + _, x172 = fiat_pasta_fq_addcarryx_u64(x150, x166, 0x0) + var x173 uint64 + var x174 fiat_pasta_fq_uint1 + x173, x174 = fiat_pasta_fq_addcarryx_u64(x152, x168, x172) + var x175 uint64 + var x176 fiat_pasta_fq_uint1 + x175, x176 = fiat_pasta_fq_addcarryx_u64(x154, x170, x174) + var x177 uint64 + var x178 fiat_pasta_fq_uint1 + x177, x178 = fiat_pasta_fq_addcarryx_u64(x156, x162, x176) + var x179 uint64 + var x180 fiat_pasta_fq_uint1 + x179, x180 = fiat_pasta_fq_addcarryx_u64(x158, x163, x178) + x181 := (uint64(x180) + uint64(x159)) + var x182 uint64 + var x183 fiat_pasta_fq_uint1 + x182, x183 = fiat_pasta_fq_subborrowx_u64(x173, 0x8c46eb2100000001, 0x0) + var x184 uint64 + var x185 fiat_pasta_fq_uint1 + x184, x185 = fiat_pasta_fq_subborrowx_u64(x175, 0x224698fc0994a8dd, x183) + var x186 uint64 + var x187 fiat_pasta_fq_uint1 + x186, x187 = fiat_pasta_fq_subborrowx_u64(x177, uint64(0x0), x185) + var x188 uint64 + var x189 fiat_pasta_fq_uint1 + x188, x189 = fiat_pasta_fq_subborrowx_u64(x179, 0x4000000000000000, x187) + var x191 fiat_pasta_fq_uint1 + _, x191 = fiat_pasta_fq_subborrowx_u64(x181, uint64(0x0), x189) + var x192 uint64 + fiat_pasta_fq_cmovznz_u64(&x192, x191, x182, x173) + var x193 uint64 + fiat_pasta_fq_cmovznz_u64(&x193, x191, x184, x175) + var x194 uint64 + fiat_pasta_fq_cmovznz_u64(&x194, x191, x186, x177) + var x195 uint64 + fiat_pasta_fq_cmovznz_u64(&x195, x191, x188, x179) + out1[0] = x192 + out1[1] = x193 + out1[2] = x194 + out1[3] = x195 +} + +// The function fiat_pasta_fq_square squares a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_square(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, arg1[3]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, arg1[1]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, arg1[0]) + var x13 uint64 + var x14 fiat_pasta_fq_uint1 + x13, x14 = fiat_pasta_fq_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fq_uint1 + x15, x16 = fiat_pasta_fq_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fq_uint1 + x17, x18 = fiat_pasta_fq_addcarryx_u64(x8, x5, x16) + x19 := (uint64(x18) + x6) + var x20 uint64 + _, x20 = bits.Mul64(x11, 0x8c46eb20ffffffff) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x20, 0x4000000000000000) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x20, 0x224698fc0994a8dd) + var x26 uint64 + var x27 uint64 + x27, x26 = bits.Mul64(x20, 0x8c46eb2100000001) + var x28 uint64 + var x29 fiat_pasta_fq_uint1 + x28, x29 = fiat_pasta_fq_addcarryx_u64(x27, x24, 0x0) + x30 := (uint64(x29) + x25) + var x32 fiat_pasta_fq_uint1 + _, x32 = fiat_pasta_fq_addcarryx_u64(x11, x26, 0x0) + var x33 uint64 + var x34 fiat_pasta_fq_uint1 + x33, x34 = fiat_pasta_fq_addcarryx_u64(x13, x28, x32) + var x35 uint64 + var x36 fiat_pasta_fq_uint1 + x35, x36 = fiat_pasta_fq_addcarryx_u64(x15, x30, x34) + var x37 uint64 + var x38 fiat_pasta_fq_uint1 + x37, x38 = fiat_pasta_fq_addcarryx_u64(x17, x22, x36) + var x39 uint64 + var x40 fiat_pasta_fq_uint1 + x39, x40 = fiat_pasta_fq_addcarryx_u64(x19, x23, x38) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, arg1[3]) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, arg1[2]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(x1, arg1[1]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(x1, arg1[0]) + var x49 uint64 + var x50 fiat_pasta_fq_uint1 + x49, x50 = fiat_pasta_fq_addcarryx_u64(x48, x45, 0x0) + var x51 uint64 + var x52 fiat_pasta_fq_uint1 + x51, x52 = fiat_pasta_fq_addcarryx_u64(x46, x43, x50) + var x53 uint64 + var x54 fiat_pasta_fq_uint1 + x53, x54 = fiat_pasta_fq_addcarryx_u64(x44, x41, x52) + x55 := (uint64(x54) + x42) + var x56 uint64 + var x57 fiat_pasta_fq_uint1 + x56, x57 = fiat_pasta_fq_addcarryx_u64(x33, x47, 0x0) + var x58 uint64 + var x59 fiat_pasta_fq_uint1 + x58, x59 = fiat_pasta_fq_addcarryx_u64(x35, x49, x57) + var x60 uint64 + var x61 fiat_pasta_fq_uint1 + x60, x61 = fiat_pasta_fq_addcarryx_u64(x37, x51, x59) + var x62 uint64 + var x63 fiat_pasta_fq_uint1 + x62, x63 = fiat_pasta_fq_addcarryx_u64(x39, x53, x61) + var x64 uint64 + var x65 fiat_pasta_fq_uint1 + x64, x65 = fiat_pasta_fq_addcarryx_u64(uint64(x40), x55, x63) + var x66 uint64 + _, x66 = bits.Mul64(x56, 0x8c46eb20ffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc0994a8dd) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x8c46eb2100000001) + var x74 uint64 + var x75 fiat_pasta_fq_uint1 + x74, x75 = fiat_pasta_fq_addcarryx_u64(x73, x70, 0x0) + x76 := (uint64(x75) + x71) + var x78 fiat_pasta_fq_uint1 + _, x78 = fiat_pasta_fq_addcarryx_u64(x56, x72, 0x0) + var x79 uint64 + var x80 fiat_pasta_fq_uint1 + x79, x80 = fiat_pasta_fq_addcarryx_u64(x58, x74, x78) + var x81 uint64 + var x82 fiat_pasta_fq_uint1 + x81, x82 = fiat_pasta_fq_addcarryx_u64(x60, x76, x80) + var x83 uint64 + var x84 fiat_pasta_fq_uint1 + x83, x84 = fiat_pasta_fq_addcarryx_u64(x62, x68, x82) + var x85 uint64 + var x86 fiat_pasta_fq_uint1 + x85, x86 = fiat_pasta_fq_addcarryx_u64(x64, x69, x84) + x87 := (uint64(x86) + uint64(x65)) + var x88 uint64 + var x89 uint64 + x89, x88 = bits.Mul64(x2, arg1[3]) + var x90 uint64 + var x91 uint64 + x91, x90 = bits.Mul64(x2, arg1[2]) + var x92 uint64 + var x93 uint64 + x93, x92 = bits.Mul64(x2, arg1[1]) + var x94 uint64 + var x95 uint64 + x95, x94 = bits.Mul64(x2, arg1[0]) + var x96 uint64 + var x97 fiat_pasta_fq_uint1 + x96, x97 = fiat_pasta_fq_addcarryx_u64(x95, x92, 0x0) + var x98 uint64 + var x99 fiat_pasta_fq_uint1 + x98, x99 = fiat_pasta_fq_addcarryx_u64(x93, x90, x97) + var x100 uint64 + var x101 fiat_pasta_fq_uint1 + x100, x101 = fiat_pasta_fq_addcarryx_u64(x91, x88, x99) + x102 := (uint64(x101) + x89) + var x103 uint64 + var x104 fiat_pasta_fq_uint1 + x103, x104 = fiat_pasta_fq_addcarryx_u64(x79, x94, 0x0) + var x105 uint64 + var x106 fiat_pasta_fq_uint1 + x105, x106 = fiat_pasta_fq_addcarryx_u64(x81, x96, x104) + var x107 uint64 + var x108 fiat_pasta_fq_uint1 + x107, x108 = fiat_pasta_fq_addcarryx_u64(x83, x98, x106) + var x109 uint64 + var x110 fiat_pasta_fq_uint1 + x109, x110 = fiat_pasta_fq_addcarryx_u64(x85, x100, x108) + var x111 uint64 + var x112 fiat_pasta_fq_uint1 + x111, x112 = fiat_pasta_fq_addcarryx_u64(x87, x102, x110) + var x113 uint64 + _, x113 = bits.Mul64(x103, 0x8c46eb20ffffffff) + var x115 uint64 + var x116 uint64 + x116, x115 = bits.Mul64(x113, 0x4000000000000000) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x113, 0x224698fc0994a8dd) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x113, 0x8c46eb2100000001) + var x121 uint64 + var x122 fiat_pasta_fq_uint1 + x121, x122 = fiat_pasta_fq_addcarryx_u64(x120, x117, 0x0) + x123 := (uint64(x122) + x118) + var x125 fiat_pasta_fq_uint1 + _, x125 = fiat_pasta_fq_addcarryx_u64(x103, x119, 0x0) + var x126 uint64 + var x127 fiat_pasta_fq_uint1 + x126, x127 = fiat_pasta_fq_addcarryx_u64(x105, x121, x125) + var x128 uint64 + var x129 fiat_pasta_fq_uint1 + x128, x129 = fiat_pasta_fq_addcarryx_u64(x107, x123, x127) + var x130 uint64 + var x131 fiat_pasta_fq_uint1 + x130, x131 = fiat_pasta_fq_addcarryx_u64(x109, x115, x129) + var x132 uint64 + var x133 fiat_pasta_fq_uint1 + x132, x133 = fiat_pasta_fq_addcarryx_u64(x111, x116, x131) + x134 := (uint64(x133) + uint64(x112)) + var x135 uint64 + var x136 uint64 + x136, x135 = bits.Mul64(x3, arg1[3]) + var x137 uint64 + var x138 uint64 + x138, x137 = bits.Mul64(x3, arg1[2]) + var x139 uint64 + var x140 uint64 + x140, x139 = bits.Mul64(x3, arg1[1]) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x3, arg1[0]) + var x143 uint64 + var x144 fiat_pasta_fq_uint1 + x143, x144 = fiat_pasta_fq_addcarryx_u64(x142, x139, 0x0) + var x145 uint64 + var x146 fiat_pasta_fq_uint1 + x145, x146 = fiat_pasta_fq_addcarryx_u64(x140, x137, x144) + var x147 uint64 + var x148 fiat_pasta_fq_uint1 + x147, x148 = fiat_pasta_fq_addcarryx_u64(x138, x135, x146) + x149 := (uint64(x148) + x136) + var x150 uint64 + var x151 fiat_pasta_fq_uint1 + x150, x151 = fiat_pasta_fq_addcarryx_u64(x126, x141, 0x0) + var x152 uint64 + var x153 fiat_pasta_fq_uint1 + x152, x153 = fiat_pasta_fq_addcarryx_u64(x128, x143, x151) + var x154 uint64 + var x155 fiat_pasta_fq_uint1 + x154, x155 = fiat_pasta_fq_addcarryx_u64(x130, x145, x153) + var x156 uint64 + var x157 fiat_pasta_fq_uint1 + x156, x157 = fiat_pasta_fq_addcarryx_u64(x132, x147, x155) + var x158 uint64 + var x159 fiat_pasta_fq_uint1 + x158, x159 = fiat_pasta_fq_addcarryx_u64(x134, x149, x157) + var x160 uint64 + _, x160 = bits.Mul64(x150, 0x8c46eb20ffffffff) + var x162 uint64 + var x163 uint64 + x163, x162 = bits.Mul64(x160, 0x4000000000000000) + var x164 uint64 + var x165 uint64 + x165, x164 = bits.Mul64(x160, 0x224698fc0994a8dd) + var x166 uint64 + var x167 uint64 + x167, x166 = bits.Mul64(x160, 0x8c46eb2100000001) + var x168 uint64 + var x169 fiat_pasta_fq_uint1 + x168, x169 = fiat_pasta_fq_addcarryx_u64(x167, x164, 0x0) + x170 := (uint64(x169) + x165) + var x172 fiat_pasta_fq_uint1 + _, x172 = fiat_pasta_fq_addcarryx_u64(x150, x166, 0x0) + var x173 uint64 + var x174 fiat_pasta_fq_uint1 + x173, x174 = fiat_pasta_fq_addcarryx_u64(x152, x168, x172) + var x175 uint64 + var x176 fiat_pasta_fq_uint1 + x175, x176 = fiat_pasta_fq_addcarryx_u64(x154, x170, x174) + var x177 uint64 + var x178 fiat_pasta_fq_uint1 + x177, x178 = fiat_pasta_fq_addcarryx_u64(x156, x162, x176) + var x179 uint64 + var x180 fiat_pasta_fq_uint1 + x179, x180 = fiat_pasta_fq_addcarryx_u64(x158, x163, x178) + x181 := (uint64(x180) + uint64(x159)) + var x182 uint64 + var x183 fiat_pasta_fq_uint1 + x182, x183 = fiat_pasta_fq_subborrowx_u64(x173, 0x8c46eb2100000001, 0x0) + var x184 uint64 + var x185 fiat_pasta_fq_uint1 + x184, x185 = fiat_pasta_fq_subborrowx_u64(x175, 0x224698fc0994a8dd, x183) + var x186 uint64 + var x187 fiat_pasta_fq_uint1 + x186, x187 = fiat_pasta_fq_subborrowx_u64(x177, uint64(0x0), x185) + var x188 uint64 + var x189 fiat_pasta_fq_uint1 + x188, x189 = fiat_pasta_fq_subborrowx_u64(x179, 0x4000000000000000, x187) + var x191 fiat_pasta_fq_uint1 + _, x191 = fiat_pasta_fq_subborrowx_u64(x181, uint64(0x0), x189) + var x192 uint64 + fiat_pasta_fq_cmovznz_u64(&x192, x191, x182, x173) + var x193 uint64 + fiat_pasta_fq_cmovznz_u64(&x193, x191, x184, x175) + var x194 uint64 + fiat_pasta_fq_cmovznz_u64(&x194, x191, x186, x177) + var x195 uint64 + fiat_pasta_fq_cmovznz_u64(&x195, x191, x188, x179) + out1[0] = x192 + out1[1] = x193 + out1[2] = x194 + out1[3] = x195 +} + +// The function fiat_pasta_fq_add adds two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_add(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element, arg2 *fiat_pasta_fq_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fq_uint1 + x1, x2 = fiat_pasta_fq_addcarryx_u64(arg1[0], arg2[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fq_uint1 + x3, x4 = fiat_pasta_fq_addcarryx_u64(arg1[1], arg2[1], x2) + var x5 uint64 + var x6 fiat_pasta_fq_uint1 + x5, x6 = fiat_pasta_fq_addcarryx_u64(arg1[2], arg2[2], x4) + var x7 uint64 + var x8 fiat_pasta_fq_uint1 + x7, x8 = fiat_pasta_fq_addcarryx_u64(arg1[3], arg2[3], x6) + var x9 uint64 + var x10 fiat_pasta_fq_uint1 + x9, x10 = fiat_pasta_fq_subborrowx_u64(x1, 0x8c46eb2100000001, 0x0) + var x11 uint64 + var x12 fiat_pasta_fq_uint1 + x11, x12 = fiat_pasta_fq_subborrowx_u64(x3, 0x224698fc0994a8dd, x10) + var x13 uint64 + var x14 fiat_pasta_fq_uint1 + x13, x14 = fiat_pasta_fq_subborrowx_u64(x5, uint64(0x0), x12) + var x15 uint64 + var x16 fiat_pasta_fq_uint1 + x15, x16 = fiat_pasta_fq_subborrowx_u64(x7, 0x4000000000000000, x14) + var x18 fiat_pasta_fq_uint1 + _, x18 = fiat_pasta_fq_subborrowx_u64(uint64(x8), uint64(0x0), x16) + var x19 uint64 + fiat_pasta_fq_cmovznz_u64(&x19, x18, x9, x1) + var x20 uint64 + fiat_pasta_fq_cmovznz_u64(&x20, x18, x11, x3) + var x21 uint64 + fiat_pasta_fq_cmovznz_u64(&x21, x18, x13, x5) + var x22 uint64 + fiat_pasta_fq_cmovznz_u64(&x22, x18, x15, x7) + out1[0] = x19 + out1[1] = x20 + out1[2] = x21 + out1[3] = x22 +} + +// The function fiat_pasta_fq_sub subtracts two field elements in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// 0 ≤ eval arg2 < m +// Postconditions: +// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_sub(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element, arg2 *fiat_pasta_fq_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fq_uint1 + x1, x2 = fiat_pasta_fq_subborrowx_u64(arg1[0], arg2[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fq_uint1 + x3, x4 = fiat_pasta_fq_subborrowx_u64(arg1[1], arg2[1], x2) + var x5 uint64 + var x6 fiat_pasta_fq_uint1 + x5, x6 = fiat_pasta_fq_subborrowx_u64(arg1[2], arg2[2], x4) + var x7 uint64 + var x8 fiat_pasta_fq_uint1 + x7, x8 = fiat_pasta_fq_subborrowx_u64(arg1[3], arg2[3], x6) + var x9 uint64 + fiat_pasta_fq_cmovznz_u64(&x9, x8, uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 fiat_pasta_fq_uint1 + x10, x11 = fiat_pasta_fq_addcarryx_u64(x1, (x9 & 0x8c46eb2100000001), 0x0) + var x12 uint64 + var x13 fiat_pasta_fq_uint1 + x12, x13 = fiat_pasta_fq_addcarryx_u64(x3, (x9 & 0x224698fc0994a8dd), x11) + var x14 uint64 + var x15 fiat_pasta_fq_uint1 + x14, x15 = fiat_pasta_fq_addcarryx_u64(x5, uint64(0x0), x13) + var x16 uint64 + x16, _ = fiat_pasta_fq_addcarryx_u64(x7, (x9 & 0x4000000000000000), x15) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// The function fiat_pasta_fq_opp negates a field element in the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_opp(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element) { + var x1 uint64 + var x2 fiat_pasta_fq_uint1 + x1, x2 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), arg1[0], 0x0) + var x3 uint64 + var x4 fiat_pasta_fq_uint1 + x3, x4 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), arg1[1], x2) + var x5 uint64 + var x6 fiat_pasta_fq_uint1 + x5, x6 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), arg1[2], x4) + var x7 uint64 + var x8 fiat_pasta_fq_uint1 + x7, x8 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), arg1[3], x6) + var x9 uint64 + fiat_pasta_fq_cmovznz_u64(&x9, x8, uint64(0x0), 0xffffffffffffffff) + var x10 uint64 + var x11 fiat_pasta_fq_uint1 + x10, x11 = fiat_pasta_fq_addcarryx_u64(x1, (x9 & 0x8c46eb2100000001), 0x0) + var x12 uint64 + var x13 fiat_pasta_fq_uint1 + x12, x13 = fiat_pasta_fq_addcarryx_u64(x3, (x9 & 0x224698fc0994a8dd), x11) + var x14 uint64 + var x15 fiat_pasta_fq_uint1 + x14, x15 = fiat_pasta_fq_addcarryx_u64(x5, uint64(0x0), x13) + var x16 uint64 + x16, _ = fiat_pasta_fq_addcarryx_u64(x7, (x9 & 0x4000000000000000), x15) + out1[0] = x10 + out1[1] = x12 + out1[2] = x14 + out1[3] = x16 +} + +// The function fiat_pasta_fq_from_montgomery translates a field element out of the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_from_montgomery(out1 *fiat_pasta_fq_non_montgomery_domain_field_element, arg1 *fiat_pasta_fq_montgomery_domain_field_element) { + x1 := arg1[0] + var x2 uint64 + _, x2 = bits.Mul64(x1, 0x8c46eb20ffffffff) + var x4 uint64 + var x5 uint64 + x5, x4 = bits.Mul64(x2, 0x4000000000000000) + var x6 uint64 + var x7 uint64 + x7, x6 = bits.Mul64(x2, 0x224698fc0994a8dd) + var x8 uint64 + var x9 uint64 + x9, x8 = bits.Mul64(x2, 0x8c46eb2100000001) + var x10 uint64 + var x11 fiat_pasta_fq_uint1 + x10, x11 = fiat_pasta_fq_addcarryx_u64(x9, x6, 0x0) + var x13 fiat_pasta_fq_uint1 + _, x13 = fiat_pasta_fq_addcarryx_u64(x1, x8, 0x0) + var x14 uint64 + var x15 fiat_pasta_fq_uint1 + x14, x15 = fiat_pasta_fq_addcarryx_u64(uint64(0x0), x10, x13) + var x16 uint64 + var x17 fiat_pasta_fq_uint1 + x16, x17 = fiat_pasta_fq_addcarryx_u64(x14, arg1[1], 0x0) + var x18 uint64 + _, x18 = bits.Mul64(x16, 0x8c46eb20ffffffff) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(x18, 0x4000000000000000) + var x22 uint64 + var x23 uint64 + x23, x22 = bits.Mul64(x18, 0x224698fc0994a8dd) + var x24 uint64 + var x25 uint64 + x25, x24 = bits.Mul64(x18, 0x8c46eb2100000001) + var x26 uint64 + var x27 fiat_pasta_fq_uint1 + x26, x27 = fiat_pasta_fq_addcarryx_u64(x25, x22, 0x0) + var x29 fiat_pasta_fq_uint1 + _, x29 = fiat_pasta_fq_addcarryx_u64(x16, x24, 0x0) + var x30 uint64 + var x31 fiat_pasta_fq_uint1 + x30, x31 = fiat_pasta_fq_addcarryx_u64((uint64(x17) + (uint64(x15) + (uint64(x11) + x7))), x26, x29) + var x32 uint64 + var x33 fiat_pasta_fq_uint1 + x32, x33 = fiat_pasta_fq_addcarryx_u64(x4, (uint64(x27) + x23), x31) + var x34 uint64 + var x35 fiat_pasta_fq_uint1 + x34, x35 = fiat_pasta_fq_addcarryx_u64(x5, x20, x33) + var x36 uint64 + var x37 fiat_pasta_fq_uint1 + x36, x37 = fiat_pasta_fq_addcarryx_u64(x30, arg1[2], 0x0) + var x38 uint64 + var x39 fiat_pasta_fq_uint1 + x38, x39 = fiat_pasta_fq_addcarryx_u64(x32, uint64(0x0), x37) + var x40 uint64 + var x41 fiat_pasta_fq_uint1 + x40, x41 = fiat_pasta_fq_addcarryx_u64(x34, uint64(0x0), x39) + var x42 uint64 + _, x42 = bits.Mul64(x36, 0x8c46eb20ffffffff) + var x44 uint64 + var x45 uint64 + x45, x44 = bits.Mul64(x42, 0x4000000000000000) + var x46 uint64 + var x47 uint64 + x47, x46 = bits.Mul64(x42, 0x224698fc0994a8dd) + var x48 uint64 + var x49 uint64 + x49, x48 = bits.Mul64(x42, 0x8c46eb2100000001) + var x50 uint64 + var x51 fiat_pasta_fq_uint1 + x50, x51 = fiat_pasta_fq_addcarryx_u64(x49, x46, 0x0) + var x53 fiat_pasta_fq_uint1 + _, x53 = fiat_pasta_fq_addcarryx_u64(x36, x48, 0x0) + var x54 uint64 + var x55 fiat_pasta_fq_uint1 + x54, x55 = fiat_pasta_fq_addcarryx_u64(x38, x50, x53) + var x56 uint64 + var x57 fiat_pasta_fq_uint1 + x56, x57 = fiat_pasta_fq_addcarryx_u64(x40, (uint64(x51) + x47), x55) + var x58 uint64 + var x59 fiat_pasta_fq_uint1 + x58, x59 = fiat_pasta_fq_addcarryx_u64((uint64(x41) + (uint64(x35) + x21)), x44, x57) + var x60 uint64 + var x61 fiat_pasta_fq_uint1 + x60, x61 = fiat_pasta_fq_addcarryx_u64(x54, arg1[3], 0x0) + var x62 uint64 + var x63 fiat_pasta_fq_uint1 + x62, x63 = fiat_pasta_fq_addcarryx_u64(x56, uint64(0x0), x61) + var x64 uint64 + var x65 fiat_pasta_fq_uint1 + x64, x65 = fiat_pasta_fq_addcarryx_u64(x58, uint64(0x0), x63) + var x66 uint64 + _, x66 = bits.Mul64(x60, 0x8c46eb20ffffffff) + var x68 uint64 + var x69 uint64 + x69, x68 = bits.Mul64(x66, 0x4000000000000000) + var x70 uint64 + var x71 uint64 + x71, x70 = bits.Mul64(x66, 0x224698fc0994a8dd) + var x72 uint64 + var x73 uint64 + x73, x72 = bits.Mul64(x66, 0x8c46eb2100000001) + var x74 uint64 + var x75 fiat_pasta_fq_uint1 + x74, x75 = fiat_pasta_fq_addcarryx_u64(x73, x70, 0x0) + var x77 fiat_pasta_fq_uint1 + _, x77 = fiat_pasta_fq_addcarryx_u64(x60, x72, 0x0) + var x78 uint64 + var x79 fiat_pasta_fq_uint1 + x78, x79 = fiat_pasta_fq_addcarryx_u64(x62, x74, x77) + var x80 uint64 + var x81 fiat_pasta_fq_uint1 + x80, x81 = fiat_pasta_fq_addcarryx_u64(x64, (uint64(x75) + x71), x79) + var x82 uint64 + var x83 fiat_pasta_fq_uint1 + x82, x83 = fiat_pasta_fq_addcarryx_u64((uint64(x65) + (uint64(x59) + x45)), x68, x81) + x84 := (uint64(x83) + x69) + var x85 uint64 + var x86 fiat_pasta_fq_uint1 + x85, x86 = fiat_pasta_fq_subborrowx_u64(x78, 0x8c46eb2100000001, 0x0) + var x87 uint64 + var x88 fiat_pasta_fq_uint1 + x87, x88 = fiat_pasta_fq_subborrowx_u64(x80, 0x224698fc0994a8dd, x86) + var x89 uint64 + var x90 fiat_pasta_fq_uint1 + x89, x90 = fiat_pasta_fq_subborrowx_u64(x82, uint64(0x0), x88) + var x91 uint64 + var x92 fiat_pasta_fq_uint1 + x91, x92 = fiat_pasta_fq_subborrowx_u64(x84, 0x4000000000000000, x90) + var x94 fiat_pasta_fq_uint1 + _, x94 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), uint64(0x0), x92) + var x95 uint64 + fiat_pasta_fq_cmovznz_u64(&x95, x94, x85, x78) + var x96 uint64 + fiat_pasta_fq_cmovznz_u64(&x96, x94, x87, x80) + var x97 uint64 + fiat_pasta_fq_cmovznz_u64(&x97, x94, x89, x82) + var x98 uint64 + fiat_pasta_fq_cmovznz_u64(&x98, x94, x91, x84) + out1[0] = x95 + out1[1] = x96 + out1[2] = x97 + out1[3] = x98 +} + +// The function fiat_pasta_fq_to_montgomery translates a field element into the Montgomery domain. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// eval (from_montgomery out1) mod m = eval arg1 mod m +// 0 ≤ eval out1 < m +// +func fiat_pasta_fq_to_montgomery(out1 *fiat_pasta_fq_montgomery_domain_field_element, arg1 *fiat_pasta_fq_non_montgomery_domain_field_element) { + x1 := arg1[1] + x2 := arg1[2] + x3 := arg1[3] + x4 := arg1[0] + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(x4, 0x96d41af7ccfdaa9) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(x4, 0x7fae231004ccf590) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(x4, 0x67bb433d891a16e3) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(x4, 0xfc9678ff0000000f) + var x13 uint64 + var x14 fiat_pasta_fq_uint1 + x13, x14 = fiat_pasta_fq_addcarryx_u64(x12, x9, 0x0) + var x15 uint64 + var x16 fiat_pasta_fq_uint1 + x15, x16 = fiat_pasta_fq_addcarryx_u64(x10, x7, x14) + var x17 uint64 + var x18 fiat_pasta_fq_uint1 + x17, x18 = fiat_pasta_fq_addcarryx_u64(x8, x5, x16) + var x19 uint64 + _, x19 = bits.Mul64(x11, 0x8c46eb20ffffffff) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(x19, 0x4000000000000000) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(x19, 0x224698fc0994a8dd) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(x19, 0x8c46eb2100000001) + var x27 uint64 + var x28 fiat_pasta_fq_uint1 + x27, x28 = fiat_pasta_fq_addcarryx_u64(x26, x23, 0x0) + var x30 fiat_pasta_fq_uint1 + _, x30 = fiat_pasta_fq_addcarryx_u64(x11, x25, 0x0) + var x31 uint64 + var x32 fiat_pasta_fq_uint1 + x31, x32 = fiat_pasta_fq_addcarryx_u64(x13, x27, x30) + var x33 uint64 + var x34 fiat_pasta_fq_uint1 + x33, x34 = fiat_pasta_fq_addcarryx_u64(x15, (uint64(x28) + x24), x32) + var x35 uint64 + var x36 fiat_pasta_fq_uint1 + x35, x36 = fiat_pasta_fq_addcarryx_u64(x17, x21, x34) + var x37 uint64 + var x38 uint64 + x38, x37 = bits.Mul64(x1, 0x96d41af7ccfdaa9) + var x39 uint64 + var x40 uint64 + x40, x39 = bits.Mul64(x1, 0x7fae231004ccf590) + var x41 uint64 + var x42 uint64 + x42, x41 = bits.Mul64(x1, 0x67bb433d891a16e3) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(x1, 0xfc9678ff0000000f) + var x45 uint64 + var x46 fiat_pasta_fq_uint1 + x45, x46 = fiat_pasta_fq_addcarryx_u64(x44, x41, 0x0) + var x47 uint64 + var x48 fiat_pasta_fq_uint1 + x47, x48 = fiat_pasta_fq_addcarryx_u64(x42, x39, x46) + var x49 uint64 + var x50 fiat_pasta_fq_uint1 + x49, x50 = fiat_pasta_fq_addcarryx_u64(x40, x37, x48) + var x51 uint64 + var x52 fiat_pasta_fq_uint1 + x51, x52 = fiat_pasta_fq_addcarryx_u64(x31, x43, 0x0) + var x53 uint64 + var x54 fiat_pasta_fq_uint1 + x53, x54 = fiat_pasta_fq_addcarryx_u64(x33, x45, x52) + var x55 uint64 + var x56 fiat_pasta_fq_uint1 + x55, x56 = fiat_pasta_fq_addcarryx_u64(x35, x47, x54) + var x57 uint64 + var x58 fiat_pasta_fq_uint1 + x57, x58 = fiat_pasta_fq_addcarryx_u64(((uint64(x36) + (uint64(x18) + x6)) + x22), x49, x56) + var x59 uint64 + _, x59 = bits.Mul64(x51, 0x8c46eb20ffffffff) + var x61 uint64 + var x62 uint64 + x62, x61 = bits.Mul64(x59, 0x4000000000000000) + var x63 uint64 + var x64 uint64 + x64, x63 = bits.Mul64(x59, 0x224698fc0994a8dd) + var x65 uint64 + var x66 uint64 + x66, x65 = bits.Mul64(x59, 0x8c46eb2100000001) + var x67 uint64 + var x68 fiat_pasta_fq_uint1 + x67, x68 = fiat_pasta_fq_addcarryx_u64(x66, x63, 0x0) + var x70 fiat_pasta_fq_uint1 + _, x70 = fiat_pasta_fq_addcarryx_u64(x51, x65, 0x0) + var x71 uint64 + var x72 fiat_pasta_fq_uint1 + x71, x72 = fiat_pasta_fq_addcarryx_u64(x53, x67, x70) + var x73 uint64 + var x74 fiat_pasta_fq_uint1 + x73, x74 = fiat_pasta_fq_addcarryx_u64(x55, (uint64(x68) + x64), x72) + var x75 uint64 + var x76 fiat_pasta_fq_uint1 + x75, x76 = fiat_pasta_fq_addcarryx_u64(x57, x61, x74) + var x77 uint64 + var x78 uint64 + x78, x77 = bits.Mul64(x2, 0x96d41af7ccfdaa9) + var x79 uint64 + var x80 uint64 + x80, x79 = bits.Mul64(x2, 0x7fae231004ccf590) + var x81 uint64 + var x82 uint64 + x82, x81 = bits.Mul64(x2, 0x67bb433d891a16e3) + var x83 uint64 + var x84 uint64 + x84, x83 = bits.Mul64(x2, 0xfc9678ff0000000f) + var x85 uint64 + var x86 fiat_pasta_fq_uint1 + x85, x86 = fiat_pasta_fq_addcarryx_u64(x84, x81, 0x0) + var x87 uint64 + var x88 fiat_pasta_fq_uint1 + x87, x88 = fiat_pasta_fq_addcarryx_u64(x82, x79, x86) + var x89 uint64 + var x90 fiat_pasta_fq_uint1 + x89, x90 = fiat_pasta_fq_addcarryx_u64(x80, x77, x88) + var x91 uint64 + var x92 fiat_pasta_fq_uint1 + x91, x92 = fiat_pasta_fq_addcarryx_u64(x71, x83, 0x0) + var x93 uint64 + var x94 fiat_pasta_fq_uint1 + x93, x94 = fiat_pasta_fq_addcarryx_u64(x73, x85, x92) + var x95 uint64 + var x96 fiat_pasta_fq_uint1 + x95, x96 = fiat_pasta_fq_addcarryx_u64(x75, x87, x94) + var x97 uint64 + var x98 fiat_pasta_fq_uint1 + x97, x98 = fiat_pasta_fq_addcarryx_u64(((uint64(x76) + (uint64(x58) + (uint64(x50) + x38))) + x62), x89, x96) + var x99 uint64 + _, x99 = bits.Mul64(x91, 0x8c46eb20ffffffff) + var x101 uint64 + var x102 uint64 + x102, x101 = bits.Mul64(x99, 0x4000000000000000) + var x103 uint64 + var x104 uint64 + x104, x103 = bits.Mul64(x99, 0x224698fc0994a8dd) + var x105 uint64 + var x106 uint64 + x106, x105 = bits.Mul64(x99, 0x8c46eb2100000001) + var x107 uint64 + var x108 fiat_pasta_fq_uint1 + x107, x108 = fiat_pasta_fq_addcarryx_u64(x106, x103, 0x0) + var x110 fiat_pasta_fq_uint1 + _, x110 = fiat_pasta_fq_addcarryx_u64(x91, x105, 0x0) + var x111 uint64 + var x112 fiat_pasta_fq_uint1 + x111, x112 = fiat_pasta_fq_addcarryx_u64(x93, x107, x110) + var x113 uint64 + var x114 fiat_pasta_fq_uint1 + x113, x114 = fiat_pasta_fq_addcarryx_u64(x95, (uint64(x108) + x104), x112) + var x115 uint64 + var x116 fiat_pasta_fq_uint1 + x115, x116 = fiat_pasta_fq_addcarryx_u64(x97, x101, x114) + var x117 uint64 + var x118 uint64 + x118, x117 = bits.Mul64(x3, 0x96d41af7ccfdaa9) + var x119 uint64 + var x120 uint64 + x120, x119 = bits.Mul64(x3, 0x7fae231004ccf590) + var x121 uint64 + var x122 uint64 + x122, x121 = bits.Mul64(x3, 0x67bb433d891a16e3) + var x123 uint64 + var x124 uint64 + x124, x123 = bits.Mul64(x3, 0xfc9678ff0000000f) + var x125 uint64 + var x126 fiat_pasta_fq_uint1 + x125, x126 = fiat_pasta_fq_addcarryx_u64(x124, x121, 0x0) + var x127 uint64 + var x128 fiat_pasta_fq_uint1 + x127, x128 = fiat_pasta_fq_addcarryx_u64(x122, x119, x126) + var x129 uint64 + var x130 fiat_pasta_fq_uint1 + x129, x130 = fiat_pasta_fq_addcarryx_u64(x120, x117, x128) + var x131 uint64 + var x132 fiat_pasta_fq_uint1 + x131, x132 = fiat_pasta_fq_addcarryx_u64(x111, x123, 0x0) + var x133 uint64 + var x134 fiat_pasta_fq_uint1 + x133, x134 = fiat_pasta_fq_addcarryx_u64(x113, x125, x132) + var x135 uint64 + var x136 fiat_pasta_fq_uint1 + x135, x136 = fiat_pasta_fq_addcarryx_u64(x115, x127, x134) + var x137 uint64 + var x138 fiat_pasta_fq_uint1 + x137, x138 = fiat_pasta_fq_addcarryx_u64(((uint64(x116) + (uint64(x98) + (uint64(x90) + x78))) + x102), x129, x136) + var x139 uint64 + _, x139 = bits.Mul64(x131, 0x8c46eb20ffffffff) + var x141 uint64 + var x142 uint64 + x142, x141 = bits.Mul64(x139, 0x4000000000000000) + var x143 uint64 + var x144 uint64 + x144, x143 = bits.Mul64(x139, 0x224698fc0994a8dd) + var x145 uint64 + var x146 uint64 + x146, x145 = bits.Mul64(x139, 0x8c46eb2100000001) + var x147 uint64 + var x148 fiat_pasta_fq_uint1 + x147, x148 = fiat_pasta_fq_addcarryx_u64(x146, x143, 0x0) + var x150 fiat_pasta_fq_uint1 + _, x150 = fiat_pasta_fq_addcarryx_u64(x131, x145, 0x0) + var x151 uint64 + var x152 fiat_pasta_fq_uint1 + x151, x152 = fiat_pasta_fq_addcarryx_u64(x133, x147, x150) + var x153 uint64 + var x154 fiat_pasta_fq_uint1 + x153, x154 = fiat_pasta_fq_addcarryx_u64(x135, (uint64(x148) + x144), x152) + var x155 uint64 + var x156 fiat_pasta_fq_uint1 + x155, x156 = fiat_pasta_fq_addcarryx_u64(x137, x141, x154) + x157 := ((uint64(x156) + (uint64(x138) + (uint64(x130) + x118))) + x142) + var x158 uint64 + var x159 fiat_pasta_fq_uint1 + x158, x159 = fiat_pasta_fq_subborrowx_u64(x151, 0x8c46eb2100000001, 0x0) + var x160 uint64 + var x161 fiat_pasta_fq_uint1 + x160, x161 = fiat_pasta_fq_subborrowx_u64(x153, 0x224698fc0994a8dd, x159) + var x162 uint64 + var x163 fiat_pasta_fq_uint1 + x162, x163 = fiat_pasta_fq_subborrowx_u64(x155, uint64(0x0), x161) + var x164 uint64 + var x165 fiat_pasta_fq_uint1 + x164, x165 = fiat_pasta_fq_subborrowx_u64(x157, 0x4000000000000000, x163) + var x167 fiat_pasta_fq_uint1 + _, x167 = fiat_pasta_fq_subborrowx_u64(uint64(0x0), uint64(0x0), x165) + var x168 uint64 + fiat_pasta_fq_cmovznz_u64(&x168, x167, x158, x151) + var x169 uint64 + fiat_pasta_fq_cmovznz_u64(&x169, x167, x160, x153) + var x170 uint64 + fiat_pasta_fq_cmovznz_u64(&x170, x167, x162, x155) + var x171 uint64 + fiat_pasta_fq_cmovznz_u64(&x171, x167, x164, x157) + out1[0] = x168 + out1[1] = x169 + out1[2] = x170 + out1[3] = x171 +} + +// The function fiat_pasta_fq_selectznz is a multi-limb conditional select. +// +// Postconditions: +// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func fiat_pasta_fq_selectznz(out1 *[4]uint64, arg1 fiat_pasta_fq_uint1, arg2 *[4]uint64, arg3 *[4]uint64) { + var x1 uint64 + fiat_pasta_fq_cmovznz_u64(&x1, arg1, arg2[0], arg3[0]) + var x2 uint64 + fiat_pasta_fq_cmovznz_u64(&x2, arg1, arg2[1], arg3[1]) + var x3 uint64 + fiat_pasta_fq_cmovznz_u64(&x3, arg1, arg2[2], arg3[2]) + var x4 uint64 + fiat_pasta_fq_cmovznz_u64(&x4, arg1, arg2[3], arg3[3]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 +} + +// The function fiat_pasta_fq_to_bytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order. +// +// Preconditions: +// 0 ≤ eval arg1 < m +// Postconditions: +// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31] +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x7fffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x7f]] +func fiat_pasta_fq_to_bytes(out1 *[32]uint8, arg1 *[4]uint64) { + x1 := arg1[3] + x2 := arg1[2] + x3 := arg1[1] + x4 := arg1[0] + x5 := (uint8(x4) & 0xff) + x6 := (x4 >> 8) + x7 := (uint8(x6) & 0xff) + x8 := (x6 >> 8) + x9 := (uint8(x8) & 0xff) + x10 := (x8 >> 8) + x11 := (uint8(x10) & 0xff) + x12 := (x10 >> 8) + x13 := (uint8(x12) & 0xff) + x14 := (x12 >> 8) + x15 := (uint8(x14) & 0xff) + x16 := (x14 >> 8) + x17 := (uint8(x16) & 0xff) + x18 := uint8((x16 >> 8)) + x19 := (uint8(x3) & 0xff) + x20 := (x3 >> 8) + x21 := (uint8(x20) & 0xff) + x22 := (x20 >> 8) + x23 := (uint8(x22) & 0xff) + x24 := (x22 >> 8) + x25 := (uint8(x24) & 0xff) + x26 := (x24 >> 8) + x27 := (uint8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (uint8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (uint8(x30) & 0xff) + x32 := uint8((x30 >> 8)) + x33 := (uint8(x2) & 0xff) + x34 := (x2 >> 8) + x35 := (uint8(x34) & 0xff) + x36 := (x34 >> 8) + x37 := (uint8(x36) & 0xff) + x38 := (x36 >> 8) + x39 := (uint8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (uint8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (uint8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (uint8(x44) & 0xff) + x46 := uint8((x44 >> 8)) + x47 := (uint8(x1) & 0xff) + x48 := (x1 >> 8) + x49 := (uint8(x48) & 0xff) + x50 := (x48 >> 8) + x51 := (uint8(x50) & 0xff) + x52 := (x50 >> 8) + x53 := (uint8(x52) & 0xff) + x54 := (x52 >> 8) + x55 := (uint8(x54) & 0xff) + x56 := (x54 >> 8) + x57 := (uint8(x56) & 0xff) + x58 := (x56 >> 8) + x59 := (uint8(x58) & 0xff) + x60 := uint8((x58 >> 8)) + out1[0] = x5 + out1[1] = x7 + out1[2] = x9 + out1[3] = x11 + out1[4] = x13 + out1[5] = x15 + out1[6] = x17 + out1[7] = x18 + out1[8] = x19 + out1[9] = x21 + out1[10] = x23 + out1[11] = x25 + out1[12] = x27 + out1[13] = x29 + out1[14] = x31 + out1[15] = x32 + out1[16] = x33 + out1[17] = x35 + out1[18] = x37 + out1[19] = x39 + out1[20] = x41 + out1[21] = x43 + out1[22] = x45 + out1[23] = x46 + out1[24] = x47 + out1[25] = x49 + out1[26] = x51 + out1[27] = x53 + out1[28] = x55 + out1[29] = x57 + out1[30] = x59 + out1[31] = x60 +} + +// The function fiat_pasta_fq_from_bytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order. +// +// Preconditions: +// 0 ≤ bytes_eval arg1 < m +// Postconditions: +// eval out1 mod m = bytes_eval arg1 mod m +// 0 ≤ eval out1 < m +// +// Input Bounds: +// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x7f]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x7fffffffffffffff]] +func fiat_pasta_fq_from_bytes(out1 *[4]uint64, arg1 *[32]uint8) { + x1 := (uint64(arg1[31]) << 56) + x2 := (uint64(arg1[30]) << 48) + x3 := (uint64(arg1[29]) << 40) + x4 := (uint64(arg1[28]) << 32) + x5 := (uint64(arg1[27]) << 24) + x6 := (uint64(arg1[26]) << 16) + x7 := (uint64(arg1[25]) << 8) + x8 := arg1[24] + x9 := (uint64(arg1[23]) << 56) + x10 := (uint64(arg1[22]) << 48) + x11 := (uint64(arg1[21]) << 40) + x12 := (uint64(arg1[20]) << 32) + x13 := (uint64(arg1[19]) << 24) + x14 := (uint64(arg1[18]) << 16) + x15 := (uint64(arg1[17]) << 8) + x16 := arg1[16] + x17 := (uint64(arg1[15]) << 56) + x18 := (uint64(arg1[14]) << 48) + x19 := (uint64(arg1[13]) << 40) + x20 := (uint64(arg1[12]) << 32) + x21 := (uint64(arg1[11]) << 24) + x22 := (uint64(arg1[10]) << 16) + x23 := (uint64(arg1[9]) << 8) + x24 := arg1[8] + x25 := (uint64(arg1[7]) << 56) + x26 := (uint64(arg1[6]) << 48) + x27 := (uint64(arg1[5]) << 40) + x28 := (uint64(arg1[4]) << 32) + x29 := (uint64(arg1[3]) << 24) + x30 := (uint64(arg1[2]) << 16) + x31 := (uint64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + uint64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x25 + x38) + x40 := (x23 + uint64(x24)) + x41 := (x22 + x40) + x42 := (x21 + x41) + x43 := (x20 + x42) + x44 := (x19 + x43) + x45 := (x18 + x44) + x46 := (x17 + x45) + x47 := (x15 + uint64(x16)) + x48 := (x14 + x47) + x49 := (x13 + x48) + x50 := (x12 + x49) + x51 := (x11 + x50) + x52 := (x10 + x51) + x53 := (x9 + x52) + x54 := (x7 + uint64(x8)) + x55 := (x6 + x54) + x56 := (x5 + x55) + x57 := (x4 + x56) + x58 := (x3 + x57) + x59 := (x2 + x58) + x60 := (x1 + x59) + out1[0] = x39 + out1[1] = x46 + out1[2] = x53 + out1[3] = x60 +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/point.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/point.go new file mode 100644 index 0000000000..bf11d2bdc1 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/native/point.go @@ -0,0 +1,468 @@ +package native + +import ( + "crypto/sha256" + "crypto/sha512" + "fmt" + "hash" + "io" + "math/big" + + "github.com/pkg/errors" + "golang.org/x/crypto/blake2b" + "golang.org/x/crypto/sha3" +) + +// EllipticPointHashType is to indicate which expand operation is used +// for hash to curve operations +type EllipticPointHashType uint + +// EllipticPointHashName is to indicate the hash function is used +// for hash to curve operations +type EllipticPointHashName uint + +const ( + // XMD - use ExpandMsgXmd + XMD EllipticPointHashType = iota + // XOF - use ExpandMsgXof + XOF +) + +const ( + SHA256 EllipticPointHashName = iota + SHA512 + SHA3_256 + SHA3_384 + SHA3_512 + BLAKE2B + SHAKE128 + SHAKE256 +) + +// EllipticPoint represents a Weierstrauss elliptic curve point +type EllipticPoint struct { + X *Field + Y *Field + Z *Field + Params *EllipticPointParams + Arithmetic EllipticPointArithmetic +} + +// EllipticPointParams are the Weierstrauss curve parameters +// such as the name, the coefficients the generator point, +// and the prime bit size +type EllipticPointParams struct { + Name string + A *Field + B *Field + Gx *Field + Gy *Field + BitSize int +} + +// EllipticPointHasher is the type of hashing methods for +// hashing byte sequences to curve point. +type EllipticPointHasher struct { + name EllipticPointHashName + hashType EllipticPointHashType + xmd hash.Hash + xof sha3.ShakeHash +} + +// Name returns the hash name for this hasher +func (e *EllipticPointHasher) Name() string { + return e.name.String() +} + +// Type returns the hash type for this hasher +func (e *EllipticPointHasher) Type() EllipticPointHashType { + return e.hashType +} + +// Xmd returns the hash method for ExpandMsgXmd +func (e *EllipticPointHasher) Xmd() hash.Hash { + return e.xmd +} + +// Xof returns the hash method for ExpandMsgXof +func (e *EllipticPointHasher) Xof() sha3.ShakeHash { + return e.xof +} + +// EllipticPointHasherSha256 creates a point hasher that uses Sha256 +func EllipticPointHasherSha256() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHA256, + hashType: XMD, + xmd: sha256.New(), + } +} + +// EllipticPointHasherSha512 creates a point hasher that uses Sha512 +func EllipticPointHasherSha512() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHA512, + hashType: XMD, + xmd: sha512.New(), + } +} + +// EllipticPointHasherSha3256 creates a point hasher that uses Sha3256 +func EllipticPointHasherSha3256() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHA3_256, + hashType: XMD, + xmd: sha3.New256(), + } +} + +// EllipticPointHasherSha3384 creates a point hasher that uses Sha3384 +func EllipticPointHasherSha3384() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHA3_384, + hashType: XMD, + xmd: sha3.New384(), + } +} + +// EllipticPointHasherSha3512 creates a point hasher that uses Sha3512 +func EllipticPointHasherSha3512() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHA3_512, + hashType: XMD, + xmd: sha3.New512(), + } +} + +// EllipticPointHasherBlake2b creates a point hasher that uses Blake2b +func EllipticPointHasherBlake2b() *EllipticPointHasher { + h, _ := blake2b.New(64, []byte{}) + return &EllipticPointHasher{ + name: BLAKE2B, + hashType: XMD, + xmd: h, + } +} + +// EllipticPointHasherShake128 creates a point hasher that uses Shake128 +func EllipticPointHasherShake128() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHAKE128, + hashType: XOF, + xof: sha3.NewShake128(), + } +} + +// EllipticPointHasherShake256 creates a point hasher that uses Shake256 +func EllipticPointHasherShake256() *EllipticPointHasher { + return &EllipticPointHasher{ + name: SHAKE128, + hashType: XOF, + xof: sha3.NewShake256(), + } +} + +// EllipticPointArithmetic are the methods that specific curves +// need to implement for higher abstractions to wrap the point +type EllipticPointArithmetic interface { + // Hash a byte sequence to the curve using the specified hasher + // and dst and store the result in out + Hash(out *EllipticPoint, hasher *EllipticPointHasher, bytes, dst []byte) error + // Double arg and store the result in out + Double(out, arg *EllipticPoint) + // Add arg1 with arg2 and store the result in out + Add(out, arg1, arg2 *EllipticPoint) + // IsOnCurve tests arg if it represents a valid point on the curve + IsOnCurve(arg *EllipticPoint) bool + // ToAffine converts arg to affine coordinates storing the result in out + ToAffine(out, arg *EllipticPoint) + // RhsEq computes the right-hand side of the ecc equation + RhsEq(out, x *Field) +} + +func (t EllipticPointHashType) String() string { + switch t { + case XMD: + return "XMD" + case XOF: + return "XOF" + } + return "unknown" +} + +func (n EllipticPointHashName) String() string { + switch n { + case SHA256: + return "SHA-256" + case SHA512: + return "SHA-512" + case SHA3_256: + return "SHA3-256" + case SHA3_384: + return "SHA3-384" + case SHA3_512: + return "SHA3-512" + case BLAKE2B: + return "BLAKE2b" + case SHAKE128: + return "SHAKE-128" + case SHAKE256: + return "SHAKE-256" + } + return "unknown" +} + +// Random creates a random point on the curve +// from the specified reader +func (p *EllipticPoint) Random(reader io.Reader) (*EllipticPoint, error) { + var seed [WideFieldBytes]byte + n, err := reader.Read(seed[:]) + if err != nil { + return nil, errors.Wrap(err, "random could not read from stream") + } + if n != WideFieldBytes { + return nil, fmt.Errorf("insufficient bytes read %d when %d are needed", n, WideFieldBytes) + } + dst := []byte(fmt.Sprintf("%s_XMD:SHA-256_SSWU_RO_", p.Params.Name)) + err = p.Arithmetic.Hash(p, EllipticPointHasherSha256(), seed[:], dst) + if err != nil { + return nil, errors.Wrap(err, "ecc hash failed") + } + return p, nil +} + +// Hash uses the hasher to map bytes to a valid point +func (p *EllipticPoint) Hash(bytes []byte, hasher *EllipticPointHasher) (*EllipticPoint, error) { + dst := []byte(fmt.Sprintf("%s_%s:%s_SSWU_RO_", p.Params.Name, hasher.hashType, hasher.name)) + err := p.Arithmetic.Hash(p, hasher, bytes, dst) + if err != nil { + return nil, errors.Wrap(err, "hash failed") + } + return p, nil +} + +// Identity returns the identity point +func (p *EllipticPoint) Identity() *EllipticPoint { + p.X.SetZero() + p.Y.SetZero() + p.Z.SetZero() + return p +} + +// Generator returns the base point for the curve +func (p *EllipticPoint) Generator() *EllipticPoint { + p.X.Set(p.Params.Gx) + p.Y.Set(p.Params.Gy) + p.Z.SetOne() + return p +} + +// IsIdentity returns true if this point is at infinity +func (p *EllipticPoint) IsIdentity() bool { + return p.Z.IsZero() == 1 +} + +// Double this point +func (p *EllipticPoint) Double(point *EllipticPoint) *EllipticPoint { + p.Set(point) + p.Arithmetic.Double(p, point) + return p +} + +// Neg negates this point +func (p *EllipticPoint) Neg(point *EllipticPoint) *EllipticPoint { + p.Set(point) + p.Y.Neg(p.Y) + return p +} + +// Add adds the two points +func (p *EllipticPoint) Add(lhs, rhs *EllipticPoint) *EllipticPoint { + p.Set(lhs) + p.Arithmetic.Add(p, lhs, rhs) + return p +} + +// Sub subtracts the two points +func (p *EllipticPoint) Sub(lhs, rhs *EllipticPoint) *EllipticPoint { + p.Set(lhs) + p.Arithmetic.Add(p, lhs, new(EllipticPoint).Neg(rhs)) + return p +} + +// Mul multiplies this point by the input scalar +func (p *EllipticPoint) Mul(point *EllipticPoint, scalar *Field) *EllipticPoint { + bytes := scalar.Bytes() + precomputed := [16]*EllipticPoint{} + precomputed[0] = new(EllipticPoint).Set(point).Identity() + precomputed[1] = new(EllipticPoint).Set(point) + for i := 2; i < 16; i += 2 { + precomputed[i] = new(EllipticPoint).Set(point).Double(precomputed[i>>1]) + precomputed[i+1] = new(EllipticPoint).Set(point).Add(precomputed[i], point) + } + p.Identity() + for i := 0; i < 256; i += 4 { + // Brouwer / windowing method. window size of 4. + for j := 0; j < 4; j++ { + p.Double(p) + } + window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F + p.Add(p, precomputed[window]) + } + return p +} + +// Equal returns 1 if the two points are equal 0 otherwise. +func (p *EllipticPoint) Equal(rhs *EllipticPoint) int { + var x1, x2, y1, y2 Field + + x1.Arithmetic = p.X.Arithmetic + x2.Arithmetic = p.X.Arithmetic + y1.Arithmetic = p.Y.Arithmetic + y2.Arithmetic = p.Y.Arithmetic + + x1.Mul(p.X, rhs.Z) + x2.Mul(rhs.X, p.Z) + + y1.Mul(p.Y, rhs.Z) + y2.Mul(rhs.Y, p.Z) + + e1 := p.Z.IsZero() + e2 := rhs.Z.IsZero() + + // Both at infinity or coordinates are the same + return (e1 & e2) | (^e1 & ^e2)&x1.Equal(&x2)&y1.Equal(&y2) +} + +// Set copies clone into p +func (p *EllipticPoint) Set(clone *EllipticPoint) *EllipticPoint { + p.X = new(Field).Set(clone.X) + p.Y = new(Field).Set(clone.Y) + p.Z = new(Field).Set(clone.Z) + p.Params = clone.Params + p.Arithmetic = clone.Arithmetic + return p +} + +// BigInt returns the x and y as big.Ints in affine +func (p *EllipticPoint) BigInt() (x, y *big.Int) { + t := new(EllipticPoint).Set(p) + p.Arithmetic.ToAffine(t, p) + x = t.X.BigInt() + y = t.Y.BigInt() + return +} + +// SetBigInt creates a point from affine x, y +// and returns the point if it is on the curve +func (p *EllipticPoint) SetBigInt(x, y *big.Int) (*EllipticPoint, error) { + xx := &Field{ + Params: p.Params.Gx.Params, + Arithmetic: p.Params.Gx.Arithmetic, + } + xx.SetBigInt(x) + yy := &Field{ + Params: p.Params.Gx.Params, + Arithmetic: p.Params.Gx.Arithmetic, + } + yy.SetBigInt(y) + pp := new(EllipticPoint).Set(p) + + zero := new(Field).Set(xx).SetZero() + one := new(Field).Set(xx).SetOne() + isIdentity := xx.IsZero() & yy.IsZero() + pp.X = xx.CMove(xx, zero, isIdentity) + pp.Y = yy.CMove(yy, zero, isIdentity) + pp.Z = one.CMove(one, zero, isIdentity) + if !p.Arithmetic.IsOnCurve(pp) && isIdentity == 0 { + return nil, fmt.Errorf("invalid coordinates") + } + return p.Set(pp), nil +} + +// GetX returns the affine X coordinate +func (p *EllipticPoint) GetX() *Field { + t := new(EllipticPoint).Set(p) + p.Arithmetic.ToAffine(t, p) + return t.X +} + +// GetY returns the affine Y coordinate +func (p *EllipticPoint) GetY() *Field { + t := new(EllipticPoint).Set(p) + p.Arithmetic.ToAffine(t, p) + return t.Y +} + +// IsOnCurve determines if this point represents a valid curve point +func (p *EllipticPoint) IsOnCurve() bool { + return p.Arithmetic.IsOnCurve(p) +} + +// ToAffine converts the point into affine coordinates +func (p *EllipticPoint) ToAffine(clone *EllipticPoint) *EllipticPoint { + p.Arithmetic.ToAffine(p, clone) + return p +} + +// SumOfProducts computes the multi-exponentiation for the specified +// points and scalars and stores the result in `p`. +// Returns an error if the lengths of the arguments is not equal. +func (p *EllipticPoint) SumOfProducts(points []*EllipticPoint, scalars []*Field) (*EllipticPoint, error) { + const Upper = 256 + const W = 4 + const Windows = Upper / W // careful--use ceiling division in case this doesn't divide evenly + if len(points) != len(scalars) { + return nil, fmt.Errorf("length mismatch") + } + + bucketSize := 1 << W + windows := make([]*EllipticPoint, Windows) + bytes := make([][32]byte, len(scalars)) + buckets := make([]*EllipticPoint, bucketSize) + + for i, scalar := range scalars { + bytes[i] = scalar.Bytes() + } + for i := range windows { + windows[i] = new(EllipticPoint).Set(p).Identity() + } + + for i := 0; i < bucketSize; i++ { + buckets[i] = new(EllipticPoint).Set(p).Identity() + } + + sum := new(EllipticPoint).Set(p) + + for j := 0; j < len(windows); j++ { + for i := 0; i < bucketSize; i++ { + buckets[i].Identity() + } + + for i := 0; i < len(scalars); i++ { + // j*W to get the nibble + // >> 3 to convert to byte, / 8 + // (W * j & W) gets the nibble, mod W + // 1 << W - 1 to get the offset + index := bytes[i][j*W>>3] >> (W * j & W) & (1< 0; i-- { + sum.Add(sum, buckets[i]) + windows[j].Add(windows[j], sum) + } + } + + p.Identity() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < W; j++ { + p.Double(p) + } + + p.Add(p, windows[i]) + } + return p, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/p256_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/p256_curve.go new file mode 100644 index 0000000000..4dba487ca9 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/p256_curve.go @@ -0,0 +1,667 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + "fmt" + "io" + "math/big" + "sync" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + p256n "github.com/coinbase/kryptology/pkg/core/curves/native/p256" + "github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp" + "github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq" +) + +var oldP256InitOnce sync.Once +var oldP256 NistP256 + +type NistP256 struct { + *elliptic.CurveParams +} + +func oldP256InitAll() { + curve := elliptic.P256() + oldP256.CurveParams = curve.Params() + oldP256.P = curve.Params().P + oldP256.N = curve.Params().N + oldP256.Gx = curve.Params().Gx + oldP256.Gy = curve.Params().Gy + oldP256.B = curve.Params().B + oldP256.BitSize = curve.Params().BitSize + oldP256.Name = curve.Params().Name +} + +func NistP256Curve() *NistP256 { + oldP256InitOnce.Do(oldP256InitAll) + return &oldP256 +} + +func (curve *NistP256) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +func (curve *NistP256) IsOnCurve(x, y *big.Int) bool { + _, err := p256n.P256PointNew().SetBigInt(x, y) + return err == nil +} + +func (curve *NistP256) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + p1, err := p256n.P256PointNew().SetBigInt(x1, y1) + if err != nil { + return nil, nil + } + p2, err := p256n.P256PointNew().SetBigInt(x2, y2) + if err != nil { + return nil, nil + } + return p1.Add(p1, p2).BigInt() +} + +func (curve *NistP256) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + p1, err := p256n.P256PointNew().SetBigInt(x1, y1) + if err != nil { + return nil, nil + } + return p1.Double(p1).BigInt() +} + +func (curve *NistP256) ScalarMul(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + p1, err := p256n.P256PointNew().SetBigInt(Bx, By) + if err != nil { + return nil, nil + } + var bytes [32]byte + copy(bytes[:], internal.ReverseScalarBytes(k)) + s, err := fq.P256FqNew().SetBytes(&bytes) + if err != nil { + return nil, nil + } + return p1.Mul(p1, s).BigInt() +} + +func (curve *NistP256) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + var bytes [32]byte + copy(bytes[:], internal.ReverseScalarBytes(k)) + s, err := fq.P256FqNew().SetBytes(&bytes) + if err != nil { + return nil, nil + } + p1 := p256n.P256PointNew().Generator() + return p1.Mul(p1, s).BigInt() +} + +type ScalarP256 struct { + value *native.Field +} + +type PointP256 struct { + value *native.EllipticPoint +} + +func (s *ScalarP256) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarP256) Hash(bytes []byte) Scalar { + dst := []byte("P256_XMD:SHA-256_SSWU_RO_") + xmd := native.ExpandMsgXmd(native.EllipticPointHasherSha256(), bytes, dst, 48) + var t [64]byte + copy(t[:48], internal.ReverseScalarBytes(xmd)) + + return &ScalarP256{ + value: fq.P256FqNew().SetBytesWide(&t), + } +} + +func (s *ScalarP256) Zero() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().SetZero(), + } +} + +func (s *ScalarP256) One() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().SetOne(), + } +} + +func (s *ScalarP256) IsZero() bool { + return s.value.IsZero() == 1 +} + +func (s *ScalarP256) IsOne() bool { + return s.value.IsOne() == 1 +} + +func (s *ScalarP256) IsOdd() bool { + return s.value.Bytes()[0]&1 == 1 +} + +func (s *ScalarP256) IsEven() bool { + return s.value.Bytes()[0]&1 == 0 +} + +func (s *ScalarP256) New(value int) Scalar { + t := fq.P256FqNew() + v := big.NewInt(int64(value)) + if value < 0 { + v.Mod(v, t.Params.BiModulus) + } + return &ScalarP256{ + value: t.SetBigInt(v), + } +} + +func (s *ScalarP256) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarP256) + if ok { + return s.value.Cmp(r.value) + } else { + return -2 + } +} + +func (s *ScalarP256) Square() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().Square(s.value), + } +} + +func (s *ScalarP256) Double() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().Double(s.value), + } +} + +func (s *ScalarP256) Invert() (Scalar, error) { + value, wasInverted := fq.P256FqNew().Invert(s.value) + if !wasInverted { + return nil, fmt.Errorf("inverse doesn't exist") + } + return &ScalarP256{ + value, + }, nil +} + +func (s *ScalarP256) Sqrt() (Scalar, error) { + value, wasSquare := fq.P256FqNew().Sqrt(s.value) + if !wasSquare { + return nil, fmt.Errorf("not a square") + } + return &ScalarP256{ + value, + }, nil +} + +func (s *ScalarP256) Cube() Scalar { + value := fq.P256FqNew().Mul(s.value, s.value) + value.Mul(value, s.value) + return &ScalarP256{ + value, + } +} + +func (s *ScalarP256) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarP256) + if ok { + return &ScalarP256{ + value: fq.P256FqNew().Add(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarP256) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarP256) + if ok { + return &ScalarP256{ + value: fq.P256FqNew().Sub(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarP256) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarP256) + if ok { + return &ScalarP256{ + value: fq.P256FqNew().Mul(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarP256) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarP256) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarP256) + if ok { + v, wasInverted := fq.P256FqNew().Invert(r.value) + if !wasInverted { + return nil + } + v.Mul(v, s.value) + return &ScalarP256{value: v} + } else { + return nil + } +} + +func (s *ScalarP256) Neg() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().Neg(s.value), + } +} + +func (s *ScalarP256) SetBigInt(v *big.Int) (Scalar, error) { + if v == nil { + return nil, fmt.Errorf("'v' cannot be nil") + } + value := fq.P256FqNew().SetBigInt(v) + return &ScalarP256{ + value, + }, nil +} + +func (s *ScalarP256) BigInt() *big.Int { + return s.value.BigInt() +} + +func (s *ScalarP256) Bytes() []byte { + t := s.value.Bytes() + return internal.ReverseScalarBytes(t[:]) +} + +func (s *ScalarP256) SetBytes(bytes []byte) (Scalar, error) { + if len(bytes) != 32 { + return nil, fmt.Errorf("invalid length") + } + var seq [32]byte + copy(seq[:], internal.ReverseScalarBytes(bytes)) + value, err := fq.P256FqNew().SetBytes(&seq) + if err != nil { + return nil, err + } + return &ScalarP256{ + value, + }, nil +} + +func (s *ScalarP256) SetBytesWide(bytes []byte) (Scalar, error) { + if len(bytes) != 64 { + return nil, fmt.Errorf("invalid length") + } + var seq [64]byte + copy(seq[:], bytes) + return &ScalarP256{ + value: fq.P256FqNew().SetBytesWide(&seq), + }, nil +} + +func (s *ScalarP256) Point() Point { + return new(PointP256).Identity() +} + +func (s *ScalarP256) Clone() Scalar { + return &ScalarP256{ + value: fq.P256FqNew().Set(s.value), + } +} + +func (s *ScalarP256) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarP256) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarP256) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarP256) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarP256) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarP256) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarP256) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarP256) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarP256) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +func (p *PointP256) Random(reader io.Reader) Point { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *PointP256) Hash(bytes []byte) Point { + value, err := p256n.P256PointNew().Hash(bytes, native.EllipticPointHasherSha256()) + + // TODO: change hash to return an error also + if err != nil { + return nil + } + + return &PointP256{value} +} + +func (p *PointP256) Identity() Point { + return &PointP256{ + value: p256n.P256PointNew().Identity(), + } +} + +func (p *PointP256) Generator() Point { + return &PointP256{ + value: p256n.P256PointNew().Generator(), + } +} + +func (p *PointP256) IsIdentity() bool { + return p.value.IsIdentity() +} + +func (p *PointP256) IsNegative() bool { + return p.value.GetY().Value[0]&1 == 1 +} + +func (p *PointP256) IsOnCurve() bool { + return p.value.IsOnCurve() +} + +func (p *PointP256) Double() Point { + value := p256n.P256PointNew().Double(p.value) + return &PointP256{value} +} + +func (p *PointP256) Scalar() Scalar { + return new(ScalarP256).Zero() +} + +func (p *PointP256) Neg() Point { + value := p256n.P256PointNew().Neg(p.value) + return &PointP256{value} +} + +func (p *PointP256) Add(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointP256) + if ok { + value := p256n.P256PointNew().Add(p.value, r.value) + return &PointP256{value} + } else { + return nil + } +} + +func (p *PointP256) Sub(rhs Point) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*PointP256) + if ok { + value := p256n.P256PointNew().Sub(p.value, r.value) + return &PointP256{value} + } else { + return nil + } +} + +func (p *PointP256) Mul(rhs Scalar) Point { + if rhs == nil { + return nil + } + r, ok := rhs.(*ScalarP256) + if ok { + value := p256n.P256PointNew().Mul(p.value, r.value) + return &PointP256{value} + } else { + return nil + } +} + +func (p *PointP256) Equal(rhs Point) bool { + r, ok := rhs.(*PointP256) + if ok { + return p.value.Equal(r.value) == 1 + } else { + return false + } +} + +func (p *PointP256) Set(x, y *big.Int) (Point, error) { + value, err := p256n.P256PointNew().SetBigInt(x, y) + if err != nil { + return nil, err + } + return &PointP256{value}, nil +} + +func (p *PointP256) ToAffineCompressed() []byte { + var x [33]byte + x[0] = byte(2) + + t := p256n.P256PointNew().ToAffine(p.value) + + x[0] |= t.Y.Bytes()[0] & 1 + + xBytes := t.X.Bytes() + copy(x[1:], internal.ReverseScalarBytes(xBytes[:])) + return x[:] +} + +func (p *PointP256) ToAffineUncompressed() []byte { + var out [65]byte + out[0] = byte(4) + t := p256n.P256PointNew().ToAffine(p.value) + arr := t.X.Bytes() + copy(out[1:33], internal.ReverseScalarBytes(arr[:])) + arr = t.Y.Bytes() + copy(out[33:], internal.ReverseScalarBytes(arr[:])) + return out[:] +} + +func (p *PointP256) FromAffineCompressed(bytes []byte) (Point, error) { + var raw [native.FieldBytes]byte + if len(bytes) != 33 { + return nil, fmt.Errorf("invalid byte sequence") + } + sign := int(bytes[0]) + if sign != 2 && sign != 3 { + return nil, fmt.Errorf("invalid sign byte") + } + sign &= 0x1 + + copy(raw[:], internal.ReverseScalarBytes(bytes[1:])) + x, err := fp.P256FpNew().SetBytes(&raw) + if err != nil { + return nil, err + } + + value := p256n.P256PointNew().Identity() + rhs := fp.P256FpNew() + p.value.Arithmetic.RhsEq(rhs, x) + // test that rhs is quadratic residue + // if not, then this Point is at infinity + y, wasQr := fp.P256FpNew().Sqrt(rhs) + if wasQr { + // fix the sign + sigY := int(y.Bytes()[0] & 1) + if sigY != sign { + y.Neg(y) + } + value.X = x + value.Y = y + value.Z.SetOne() + } + return &PointP256{value}, nil +} + +func (p *PointP256) FromAffineUncompressed(bytes []byte) (Point, error) { + var arr [native.FieldBytes]byte + if len(bytes) != 65 { + return nil, fmt.Errorf("invalid byte sequence") + } + if bytes[0] != 4 { + return nil, fmt.Errorf("invalid sign byte") + } + + copy(arr[:], internal.ReverseScalarBytes(bytes[1:33])) + x, err := fp.P256FpNew().SetBytes(&arr) + if err != nil { + return nil, err + } + copy(arr[:], internal.ReverseScalarBytes(bytes[33:])) + y, err := fp.P256FpNew().SetBytes(&arr) + if err != nil { + return nil, err + } + value := p256n.P256PointNew() + value.X = x + value.Y = y + value.Z.SetOne() + return &PointP256{value}, nil +} + +func (p *PointP256) CurveName() string { + return elliptic.P256().Params().Name +} + +func (p *PointP256) SumOfProducts(points []Point, scalars []Scalar) Point { + nPoints := make([]*native.EllipticPoint, len(points)) + nScalars := make([]*native.Field, len(scalars)) + for i, pt := range points { + ptv, ok := pt.(*PointP256) + if !ok { + return nil + } + nPoints[i] = ptv.value + } + for i, sc := range scalars { + s, ok := sc.(*ScalarP256) + if !ok { + return nil + } + nScalars[i] = s.value + } + value := p256n.P256PointNew() + _, err := value.SumOfProducts(nPoints, nScalars) + if err != nil { + return nil + } + return &PointP256{value} +} + +func (p *PointP256) X() *native.Field { + return p.value.GetX() +} + +func (p *PointP256) Y() *native.Field { + return p.value.GetY() +} + +func (p *PointP256) Params() *elliptic.CurveParams { + return elliptic.P256().Params() +} + +func (p *PointP256) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointP256) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointP256) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointP256) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointP256) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointP256) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointP256) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointP256) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointP256) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/curves/pallas_curve.go b/vendor/github.com/coinbase/kryptology/pkg/core/curves/pallas_curve.go new file mode 100644 index 0000000000..93455b5507 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/curves/pallas_curve.go @@ -0,0 +1,1169 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package curves + +import ( + "crypto/elliptic" + crand "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "io" + "math/big" + "sync" + + "golang.org/x/crypto/blake2b" + + "github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp" + "github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq" +) + +var b = new(fp.Fp).SetUint64(5) +var three = &fp.Fp{0x6b0ee5d0fffffff5, 0x86f76d2b99b14bd0, 0xfffffffffffffffe, 0x3fffffffffffffff} +var eight = &fp.Fp{0x7387134cffffffe1, 0xd973797adfadd5a8, 0xfffffffffffffffb, 0x3fffffffffffffff} +var bool2int = map[bool]int{ + true: 1, + false: 0, +} + +var isomapper = [13]*fp.Fp{ + new(fp.Fp).SetRaw(&[4]uint64{0x775f6034aaaaaaab, 0x4081775473d8375b, 0xe38e38e38e38e38e, 0x0e38e38e38e38e38}), + new(fp.Fp).SetRaw(&[4]uint64{0x8cf863b02814fb76, 0x0f93b82ee4b99495, 0x267c7ffa51cf412a, 0x3509afd51872d88e}), + new(fp.Fp).SetRaw(&[4]uint64{0x0eb64faef37ea4f7, 0x380af066cfeb6d69, 0x98c7d7ac3d98fd13, 0x17329b9ec5253753}), + new(fp.Fp).SetRaw(&[4]uint64{0xeebec06955555580, 0x8102eea8e7b06eb6, 0xc71c71c71c71c71c, 0x1c71c71c71c71c71}), + new(fp.Fp).SetRaw(&[4]uint64{0xc47f2ab668bcd71f, 0x9c434ac1c96b6980, 0x5a607fcce0494a79, 0x1d572e7ddc099cff}), + new(fp.Fp).SetRaw(&[4]uint64{0x2aa3af1eae5b6604, 0xb4abf9fb9a1fc81c, 0x1d13bf2a7f22b105, 0x325669becaecd5d1}), + new(fp.Fp).SetRaw(&[4]uint64{0x5ad985b5e38e38e4, 0x7642b01ad461bad2, 0x4bda12f684bda12f, 0x1a12f684bda12f68}), + new(fp.Fp).SetRaw(&[4]uint64{0xc67c31d8140a7dbb, 0x07c9dc17725cca4a, 0x133e3ffd28e7a095, 0x1a84d7ea8c396c47}), + new(fp.Fp).SetRaw(&[4]uint64{0x02e2be87d225b234, 0x1765e924f7459378, 0x303216cce1db9ff1, 0x3fb98ff0d2ddcadd}), + new(fp.Fp).SetRaw(&[4]uint64{0x93e53ab371c71c4f, 0x0ac03e8e134eb3e4, 0x7b425ed097b425ed, 0x025ed097b425ed09}), + new(fp.Fp).SetRaw(&[4]uint64{0x5a28279b1d1b42ae, 0x5941a3a4a97aa1b3, 0x0790bfb3506defb6, 0x0c02c5bcca0e6b7f}), + new(fp.Fp).SetRaw(&[4]uint64{0x4d90ab820b12320a, 0xd976bbfabbc5661d, 0x573b3d7f7d681310, 0x17033d3c60c68173}), + new(fp.Fp).SetRaw(&[4]uint64{0x992d30ecfffffde5, 0x224698fc094cf91b, 0x0000000000000000, 0x4000000000000000}), +} +var isoa = new(fp.Fp).SetRaw(&[4]uint64{0x92bb4b0b657a014b, 0xb74134581a27a59f, 0x49be2d7258370742, 0x18354a2eb0ea8c9c}) +var isob = new(fp.Fp).SetRaw(&[4]uint64{1265, 0, 0, 0}) +var z = new(fp.Fp).SetRaw(&[4]uint64{0x992d30ecfffffff4, 0x224698fc094cf91b, 0x0000000000000000, 0x4000000000000000}) + +var oldPallasInitonce sync.Once +var oldPallas PallasCurve + +type PallasCurve struct { + *elliptic.CurveParams +} + +func oldPallasInitAll() { + oldPallas.CurveParams = new(elliptic.CurveParams) + oldPallas.P = new(big.Int).SetBytes([]byte{ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x46, 0x98, 0xfc, 0x09, 0x4c, 0xf9, 0x1b, + 0x99, 0x2d, 0x30, 0xed, 0x00, 0x00, 0x00, 0x01, + }) + oldPallas.N = new(big.Int).SetBytes([]byte{ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x46, 0x98, 0xfc, 0x09, 0x94, 0xa8, 0xdd, + 0x8c, 0x46, 0xeb, 0x21, 0x00, 0x00, 0x00, 0x01, + }) + g := new(Ep).Generator() + oldPallas.Gx = g.x.BigInt() + oldPallas.Gy = g.y.BigInt() + oldPallas.B = big.NewInt(5) + oldPallas.BitSize = 255 + pallas.Name = PallasName +} + +func Pallas() *PallasCurve { + oldPallasInitonce.Do(oldPallasInitAll) + return &oldPallas +} + +func (curve *PallasCurve) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +func (curve *PallasCurve) IsOnCurve(x, y *big.Int) bool { + p := new(Ep) + p.x = new(fp.Fp).SetBigInt(x) + p.y = new(fp.Fp).SetBigInt(y) + p.z = new(fp.Fp).SetOne() + + return p.IsOnCurve() +} + +func (curve *PallasCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + p := new(Ep) + p.x = new(fp.Fp).SetBigInt(x1) + p.y = new(fp.Fp).SetBigInt(y1) + p.z = new(fp.Fp).SetOne() + if p.x.IsZero() && p.y.IsZero() { + p.z.SetZero() + } + + q := new(Ep) + q.x = new(fp.Fp).SetBigInt(x2) + q.y = new(fp.Fp).SetBigInt(y2) + q.z = new(fp.Fp).SetOne() + if q.x.IsZero() && q.y.IsZero() { + q.z.SetZero() + } + p.Add(p, q) + p.toAffine() + return p.x.BigInt(), p.y.BigInt() +} + +func (curve *PallasCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + p := new(Ep) + p.x = new(fp.Fp).SetBigInt(x1) + p.y = new(fp.Fp).SetBigInt(y1) + p.z = new(fp.Fp).SetOne() + if p.x.IsZero() && p.y.IsZero() { + p.z.SetZero() + } + p.Double(p) + p.toAffine() + return p.x.BigInt(), p.y.BigInt() +} + +func (curve *PallasCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + p := new(Ep) + p.x = new(fp.Fp).SetBigInt(Bx) + p.y = new(fp.Fp).SetBigInt(By) + p.z = new(fp.Fp).SetOne() + if p.x.IsZero() && p.y.IsZero() { + p.z.SetZero() + } + var t [32]byte + copy(t[:], k) + ss := new(big.Int).SetBytes(k) + sc := new(fq.Fq).SetBigInt(ss) + p.Mul(p, sc) + p.toAffine() + return p.x.BigInt(), p.y.BigInt() +} + +func (curve *PallasCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + p := new(Ep).Generator() + var t [32]byte + copy(t[:], k) + ss := new(big.Int).SetBytes(k) + sc := new(fq.Fq).SetBigInt(ss) + p.Mul(p, sc) + p.toAffine() + return p.x.BigInt(), p.y.BigInt() +} + +// PallasScalar - Old interface +type PallasScalar struct{} + +func NewPallasScalar() *PallasScalar { + return &PallasScalar{} +} + +func (k PallasScalar) Add(x, y *big.Int) *big.Int { + r := new(big.Int).Add(x, y) + return r.Mod(r, fq.BiModulus) +} + +func (k PallasScalar) Sub(x, y *big.Int) *big.Int { + r := new(big.Int).Sub(x, y) + return r.Mod(r, fq.BiModulus) +} + +func (k PallasScalar) Neg(x *big.Int) *big.Int { + r := new(big.Int).Neg(x) + return r.Mod(r, fq.BiModulus) +} + +func (k PallasScalar) Mul(x, y *big.Int) *big.Int { + r := new(big.Int).Mul(x, y) + return r.Mod(r, fq.BiModulus) +} + +func (k PallasScalar) Div(x, y *big.Int) *big.Int { + r := new(big.Int).ModInverse(y, fq.BiModulus) + r.Mul(r, x) + return r.Mod(r, fq.BiModulus) +} + +func (k PallasScalar) Hash(input []byte) *big.Int { + return new(ScalarPallas).Hash(input).(*ScalarPallas).value.BigInt() +} + +func (k PallasScalar) Bytes(x *big.Int) []byte { + return x.Bytes() +} + +func (k PallasScalar) Random() (*big.Int, error) { + s, ok := new(ScalarPallas).Random(crand.Reader).(*ScalarPallas) + if !ok { + return nil, errors.New("incorrect type conversion") + } + return s.value.BigInt(), nil +} + +func (k PallasScalar) IsValid(x *big.Int) bool { + return x.Cmp(fq.BiModulus) == -1 +} + +// ScalarPallas - New interface +type ScalarPallas struct { + value *fq.Fq +} + +func (s *ScalarPallas) Random(reader io.Reader) Scalar { + if reader == nil { + return nil + } + var seed [64]byte + _, _ = reader.Read(seed[:]) + return s.Hash(seed[:]) +} + +func (s *ScalarPallas) Hash(bytes []byte) Scalar { + h, _ := blake2b.New(64, []byte{}) + xmd, err := expandMsgXmd(h, bytes, []byte("pallas_XMD:BLAKE2b_SSWU_RO_"), 64) + if err != nil { + return nil + } + var t [64]byte + copy(t[:], xmd) + return &ScalarPallas{ + value: new(fq.Fq).SetBytesWide(&t), + } +} + +func (s *ScalarPallas) Zero() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).SetZero(), + } +} + +func (s *ScalarPallas) One() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).SetOne(), + } +} + +func (s *ScalarPallas) IsZero() bool { + return s.value.IsZero() +} + +func (s *ScalarPallas) IsOne() bool { + return s.value.IsOne() +} + +func (s *ScalarPallas) IsOdd() bool { + return (s.value[0] & 1) == 1 +} + +func (s *ScalarPallas) IsEven() bool { + return (s.value[0] & 1) == 0 +} + +func (s *ScalarPallas) New(value int) Scalar { + v := big.NewInt(int64(value)) + return &ScalarPallas{ + value: new(fq.Fq).SetBigInt(v), + } +} + +func (s *ScalarPallas) Cmp(rhs Scalar) int { + r, ok := rhs.(*ScalarPallas) + if ok { + return s.value.Cmp(r.value) + } else { + return -2 + } +} + +func (s *ScalarPallas) Square() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).Square(s.value), + } +} + +func (s *ScalarPallas) Double() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).Double(s.value), + } +} + +func (s *ScalarPallas) Invert() (Scalar, error) { + value, wasInverted := new(fq.Fq).Invert(s.value) + if !wasInverted { + return nil, fmt.Errorf("inverse doesn't exist") + } + return &ScalarPallas{ + value, + }, nil +} + +func (s *ScalarPallas) Sqrt() (Scalar, error) { + value, wasSquare := new(fq.Fq).Sqrt(s.value) + if !wasSquare { + return nil, fmt.Errorf("not a square") + } + return &ScalarPallas{ + value, + }, nil +} + +func (s *ScalarPallas) Cube() Scalar { + value := new(fq.Fq).Mul(s.value, s.value) + value.Mul(value, s.value) + return &ScalarPallas{ + value, + } +} + +func (s *ScalarPallas) Add(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarPallas) + if ok { + return &ScalarPallas{ + value: new(fq.Fq).Add(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarPallas) Sub(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarPallas) + if ok { + return &ScalarPallas{ + value: new(fq.Fq).Sub(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarPallas) Mul(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarPallas) + if ok { + return &ScalarPallas{ + value: new(fq.Fq).Mul(s.value, r.value), + } + } else { + return nil + } +} + +func (s *ScalarPallas) MulAdd(y, z Scalar) Scalar { + return s.Mul(y).Add(z) +} + +func (s *ScalarPallas) Div(rhs Scalar) Scalar { + r, ok := rhs.(*ScalarPallas) + if ok { + v, wasInverted := new(fq.Fq).Invert(r.value) + if !wasInverted { + return nil + } + v.Mul(v, s.value) + return &ScalarPallas{value: v} + } else { + return nil + } +} + +func (s *ScalarPallas) Neg() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).Neg(s.value), + } +} + +func (s *ScalarPallas) SetBigInt(v *big.Int) (Scalar, error) { + return &ScalarPallas{ + value: new(fq.Fq).SetBigInt(v), + }, nil +} + +func (s *ScalarPallas) BigInt() *big.Int { + return s.value.BigInt() +} + +func (s *ScalarPallas) Bytes() []byte { + t := s.value.Bytes() + return t[:] +} + +func (s *ScalarPallas) SetBytes(bytes []byte) (Scalar, error) { + if len(bytes) != 32 { + return nil, fmt.Errorf("invalid length") + } + var seq [32]byte + copy(seq[:], bytes) + value, err := new(fq.Fq).SetBytes(&seq) + if err != nil { + return nil, err + } + return &ScalarPallas{ + value, + }, nil +} + +func (s *ScalarPallas) SetBytesWide(bytes []byte) (Scalar, error) { + if len(bytes) != 64 { + return nil, fmt.Errorf("invalid length") + } + var seq [64]byte + copy(seq[:], bytes) + return &ScalarPallas{ + value: new(fq.Fq).SetBytesWide(&seq), + }, nil +} + +func (s *ScalarPallas) Point() Point { + return new(PointPallas).Identity() +} + +func (s *ScalarPallas) Clone() Scalar { + return &ScalarPallas{ + value: new(fq.Fq).Set(s.value), + } +} + +func (s *ScalarPallas) GetFq() *fq.Fq { + return new(fq.Fq).Set(s.value) +} + +func (s *ScalarPallas) SetFq(fq *fq.Fq) *ScalarPallas { + s.value = fq + return s +} + +func (s *ScalarPallas) MarshalBinary() ([]byte, error) { + return scalarMarshalBinary(s) +} + +func (s *ScalarPallas) UnmarshalBinary(input []byte) error { + sc, err := scalarUnmarshalBinary(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarPallas) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarPallas) MarshalText() ([]byte, error) { + return scalarMarshalText(s) +} + +func (s *ScalarPallas) UnmarshalText(input []byte) error { + sc, err := scalarUnmarshalText(input) + if err != nil { + return err + } + ss, ok := sc.(*ScalarPallas) + if !ok { + return fmt.Errorf("invalid scalar") + } + s.value = ss.value + return nil +} + +func (s *ScalarPallas) MarshalJSON() ([]byte, error) { + return scalarMarshalJson(s) +} + +func (s *ScalarPallas) UnmarshalJSON(input []byte) error { + sc, err := scalarUnmarshalJson(input) + if err != nil { + return err + } + S, ok := sc.(*ScalarPallas) + if !ok { + return fmt.Errorf("invalid type") + } + s.value = S.value + return nil +} + +type PointPallas struct { + value *Ep +} + +func (p *PointPallas) Random(reader io.Reader) Point { + return &PointPallas{new(Ep).Random(reader)} +} + +func (p *PointPallas) Hash(bytes []byte) Point { + return &PointPallas{new(Ep).Hash(bytes)} +} + +func (p *PointPallas) Identity() Point { + return &PointPallas{new(Ep).Identity()} +} + +func (p *PointPallas) Generator() Point { + return &PointPallas{new(Ep).Generator()} +} + +func (p *PointPallas) IsIdentity() bool { + return p.value.IsIdentity() +} + +func (p *PointPallas) IsNegative() bool { + return p.value.Y().IsOdd() +} + +func (p *PointPallas) IsOnCurve() bool { + return p.value.IsOnCurve() +} + +func (p *PointPallas) Double() Point { + return &PointPallas{new(Ep).Double(p.value)} +} + +func (p *PointPallas) Scalar() Scalar { + return &ScalarPallas{new(fq.Fq).SetZero()} +} + +func (p *PointPallas) Neg() Point { + return &PointPallas{new(Ep).Neg(p.value)} +} + +func (p *PointPallas) Add(rhs Point) Point { + r, ok := rhs.(*PointPallas) + if !ok { + return nil + } + return &PointPallas{new(Ep).Add(p.value, r.value)} +} + +func (p *PointPallas) Sub(rhs Point) Point { + r, ok := rhs.(*PointPallas) + if !ok { + return nil + } + return &PointPallas{new(Ep).Sub(p.value, r.value)} +} + +func (p *PointPallas) Mul(rhs Scalar) Point { + s, ok := rhs.(*ScalarPallas) + if !ok { + return nil + } + return &PointPallas{new(Ep).Mul(p.value, s.value)} +} + +func (p *PointPallas) Equal(rhs Point) bool { + r, ok := rhs.(*PointPallas) + if !ok { + return false + } + return p.value.Equal(r.value) +} + +func (p *PointPallas) Set(x, y *big.Int) (Point, error) { + xx := subtle.ConstantTimeCompare(x.Bytes(), []byte{}) + yy := subtle.ConstantTimeCompare(y.Bytes(), []byte{}) + xElem := new(fp.Fp).SetBigInt(x) + var data [32]byte + if yy == 1 { + if xx == 1 { + return &PointPallas{new(Ep).Identity()}, nil + } + data = xElem.Bytes() + return p.FromAffineCompressed(data[:]) + } + yElem := new(fp.Fp).SetBigInt(y) + value := &Ep{xElem, yElem, new(fp.Fp).SetOne()} + if !value.IsOnCurve() { + return nil, fmt.Errorf("point is not on the curve") + } + return &PointPallas{value}, nil +} + +func (p *PointPallas) ToAffineCompressed() []byte { + return p.value.ToAffineCompressed() +} + +func (p *PointPallas) ToAffineUncompressed() []byte { + return p.value.ToAffineUncompressed() +} + +func (p *PointPallas) FromAffineCompressed(bytes []byte) (Point, error) { + value, err := new(Ep).FromAffineCompressed(bytes) + if err != nil { + return nil, err + } + return &PointPallas{value}, nil +} + +func (p *PointPallas) FromAffineUncompressed(bytes []byte) (Point, error) { + value, err := new(Ep).FromAffineUncompressed(bytes) + if err != nil { + return nil, err + } + return &PointPallas{value}, nil +} + +func (p *PointPallas) CurveName() string { + return PallasName +} + +func (p *PointPallas) SumOfProducts(points []Point, scalars []Scalar) Point { + eps := make([]*Ep, len(points)) + for i, pt := range points { + ps, ok := pt.(*PointPallas) + if !ok { + return nil + } + eps[i] = ps.value + } + value := p.value.SumOfProducts(eps, scalars) + return &PointPallas{value} +} + +func (p *PointPallas) MarshalBinary() ([]byte, error) { + return pointMarshalBinary(p) +} + +func (p *PointPallas) UnmarshalBinary(input []byte) error { + pt, err := pointUnmarshalBinary(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointPallas) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointPallas) MarshalText() ([]byte, error) { + return pointMarshalText(p) +} + +func (p *PointPallas) UnmarshalText(input []byte) error { + pt, err := pointUnmarshalText(input) + if err != nil { + return err + } + ppt, ok := pt.(*PointPallas) + if !ok { + return fmt.Errorf("invalid point") + } + p.value = ppt.value + return nil +} + +func (p *PointPallas) MarshalJSON() ([]byte, error) { + return pointMarshalJson(p) +} + +func (p *PointPallas) UnmarshalJSON(input []byte) error { + pt, err := pointUnmarshalJson(input) + if err != nil { + return err + } + P, ok := pt.(*PointPallas) + if !ok { + return fmt.Errorf("invalid type") + } + p.value = P.value + return nil +} + +func (p *PointPallas) X() *fp.Fp { + return p.value.X() +} + +func (p *PointPallas) Y() *fp.Fp { + return p.value.Y() +} + +func (p *PointPallas) GetEp() *Ep { + return new(Ep).Set(p.value) +} + +type Ep struct { + x *fp.Fp + y *fp.Fp + z *fp.Fp +} + +func (p *Ep) Random(reader io.Reader) *Ep { + var seed [64]byte + _, _ = reader.Read(seed[:]) + return p.Hash(seed[:]) +} + +func (p *Ep) Hash(bytes []byte) *Ep { + if bytes == nil { + bytes = []byte{} + } + h, _ := blake2b.New(64, []byte{}) + u, _ := expandMsgXmd(h, bytes, []byte("pallas_XMD:BLAKE2b_SSWU_RO_"), 128) + var buf [64]byte + copy(buf[:], u[:64]) + u0 := new(fp.Fp).SetBytesWide(&buf) + copy(buf[:], u[64:]) + u1 := new(fp.Fp).SetBytesWide(&buf) + + q0 := mapSswu(u0) + q1 := mapSswu(u1) + r1 := isoMap(q0) + r2 := isoMap(q1) + return p.Identity().Add(r1, r2) +} + +func (p *Ep) Identity() *Ep { + p.x = new(fp.Fp).SetZero() + p.y = new(fp.Fp).SetZero() + p.z = new(fp.Fp).SetZero() + return p +} + +func (p *Ep) Generator() *Ep { + p.x = new(fp.Fp).SetOne() + p.y = &fp.Fp{0x2f474795455d409d, 0xb443b9b74b8255d9, 0x270c412f2c9a5d66, 0x8e00f71ba43dd6b} + p.z = new(fp.Fp).SetOne() + return p +} + +func (p *Ep) IsIdentity() bool { + return p.z.IsZero() +} + +func (p *Ep) Double(other *Ep) *Ep { + if other.IsIdentity() { + p.Set(other) + return p + } + r := new(Ep) + // essentially paraphrased https://github.com/MinaProtocol/c-reference-signer/blob/master/crypto.c#L306-L337 + a := new(fp.Fp).Square(other.x) + b := new(fp.Fp).Square(other.y) + c := new(fp.Fp).Square(b) + r.x = new(fp.Fp).Add(other.x, b) + r.y = new(fp.Fp).Square(r.x) + r.z = new(fp.Fp).Sub(r.y, a) + r.x.Sub(r.z, c) + d := new(fp.Fp).Double(r.x) + e := new(fp.Fp).Mul(three, a) + f := new(fp.Fp).Square(e) + r.y.Double(d) + r.x.Sub(f, r.y) + r.y.Sub(d, r.x) + f.Mul(eight, c) + r.z.Mul(e, r.y) + r.y.Sub(r.z, f) + f.Mul(other.y, other.z) + r.z.Double(f) + p.Set(r) + return p +} + +func (p *Ep) Neg(other *Ep) *Ep { + p.x = new(fp.Fp).Set(other.x) + p.y = new(fp.Fp).Neg(other.y) + p.z = new(fp.Fp).Set(other.z) + return p +} + +func (p *Ep) Add(lhs *Ep, rhs *Ep) *Ep { + if lhs.IsIdentity() { + return p.Set(rhs) + } + if rhs.IsIdentity() { + return p.Set(lhs) + } + z1z1 := new(fp.Fp).Square(lhs.z) + z2z2 := new(fp.Fp).Square(rhs.z) + u1 := new(fp.Fp).Mul(lhs.x, z2z2) + u2 := new(fp.Fp).Mul(rhs.x, z1z1) + s1 := new(fp.Fp).Mul(lhs.y, z2z2) + s1.Mul(s1, rhs.z) + s2 := new(fp.Fp).Mul(rhs.y, z1z1) + s2.Mul(s2, lhs.z) + + if u1.Equal(u2) { + if s1.Equal(s2) { + return p.Double(lhs) + } else { + return p.Identity() + } + } else { + h := new(fp.Fp).Sub(u2, u1) + i := new(fp.Fp).Double(h) + i.Square(i) + j := new(fp.Fp).Mul(i, h) + r := new(fp.Fp).Sub(s2, s1) + r.Double(r) + v := new(fp.Fp).Mul(u1, i) + x3 := new(fp.Fp).Square(r) + x3.Sub(x3, j) + x3.Sub(x3, new(fp.Fp).Double(v)) + s1.Mul(s1, j) + s1.Double(s1) + y3 := new(fp.Fp).Mul(r, new(fp.Fp).Sub(v, x3)) + y3.Sub(y3, s1) + z3 := new(fp.Fp).Add(lhs.z, rhs.z) + z3.Square(z3) + z3.Sub(z3, z1z1) + z3.Sub(z3, z2z2) + z3.Mul(z3, h) + p.x = new(fp.Fp).Set(x3) + p.y = new(fp.Fp).Set(y3) + p.z = new(fp.Fp).Set(z3) + + return p + } +} + +func (p *Ep) Sub(lhs, rhs *Ep) *Ep { + return p.Add(lhs, new(Ep).Neg(rhs)) +} + +func (p *Ep) Mul(point *Ep, scalar *fq.Fq) *Ep { + bytes := scalar.Bytes() + precomputed := [16]*Ep{} + precomputed[0] = new(Ep).Identity() + precomputed[1] = new(Ep).Set(point) + for i := 2; i < 16; i += 2 { + precomputed[i] = new(Ep).Double(precomputed[i>>1]) + precomputed[i+1] = new(Ep).Add(precomputed[i], point) + } + p.Identity() + for i := 0; i < 256; i += 4 { + // Brouwer / windowing method. window size of 4. + for j := 0; j < 4; j++ { + p.Double(p) + } + window := bytes[32-1-i>>3] >> (4 - i&0x04) & 0x0F + p.Add(p, precomputed[window]) + } + return p +} + +func (p *Ep) Equal(other *Ep) bool { + // warning: requires converting both to affine + // could save slightly by modifying one so that its z-value equals the other + // this would save one inversion and a handful of multiplications + // but this is more subtle and error-prone, so going to just convert both to affine. + lhs := new(Ep).Set(p) + rhs := new(Ep).Set(other) + lhs.toAffine() + rhs.toAffine() + return lhs.x.Equal(rhs.x) && lhs.y.Equal(rhs.y) +} + +func (p *Ep) Set(other *Ep) *Ep { + // check is identity or on curve + p.x = new(fp.Fp).Set(other.x) + p.y = new(fp.Fp).Set(other.y) + p.z = new(fp.Fp).Set(other.z) + return p +} + +func (p *Ep) toAffine() *Ep { + // mutates `p` in-place to convert it to "affine" form. + if p.IsIdentity() { + // warning: control flow / not constant-time + p.x.SetZero() + p.y.SetZero() + p.z.SetOne() + return p + } + zInv3, _ := new(fp.Fp).Invert(p.z) // z is necessarily nonzero + zInv2 := new(fp.Fp).Square(zInv3) + zInv3.Mul(zInv3, zInv2) + p.x.Mul(p.x, zInv2) + p.y.Mul(p.y, zInv3) + p.z.SetOne() + return p +} + +func (p *Ep) ToAffineCompressed() []byte { + // Use ZCash encoding where infinity is all zeros + // and the top bit represents the sign of y and the + // remainder represent the x-coordinate + var inf [32]byte + p1 := new(Ep).Set(p) + p1.toAffine() + x := p1.x.Bytes() + x[31] |= (p1.y.Bytes()[0] & 1) << 7 + subtle.ConstantTimeCopy(bool2int[p1.IsIdentity()], x[:], inf[:]) + return x[:] +} + +func (p *Ep) ToAffineUncompressed() []byte { + p1 := new(Ep).Set(p) + p1.toAffine() + x := p1.x.Bytes() + y := p1.y.Bytes() + return append(x[:], y[:]...) +} + +func (p *Ep) FromAffineCompressed(bytes []byte) (*Ep, error) { + if len(bytes) != 32 { + return nil, fmt.Errorf("invalid byte sequence") + } + + var input [32]byte + copy(input[:], bytes) + sign := (input[31] >> 7) & 1 + input[31] &= 0x7F + + x := new(fp.Fp) + if _, err := x.SetBytes(&input); err != nil { + return nil, err + } + rhs := rhsPallas(x) + if _, square := rhs.Sqrt(rhs); !square { + return nil, fmt.Errorf("rhs of given x-coordinate is not a square") + } + if rhs.Bytes()[0]&1 != sign { + rhs.Neg(rhs) + } + p.x = x + p.y = rhs + p.z = new(fp.Fp).SetOne() + if !p.IsOnCurve() { + return nil, fmt.Errorf("invalid point") + } + return p, nil +} + +func (p *Ep) FromAffineUncompressed(bytes []byte) (*Ep, error) { + if len(bytes) != 64 { + return nil, fmt.Errorf("invalid length") + } + p.z = new(fp.Fp).SetOne() + p.x = new(fp.Fp) + p.y = new(fp.Fp) + var x, y [32]byte + copy(x[:], bytes[:32]) + copy(y[:], bytes[32:]) + if _, err := p.x.SetBytes(&x); err != nil { + return nil, err + } + if _, err := p.y.SetBytes(&y); err != nil { + return nil, err + } + if !p.IsOnCurve() { + return nil, fmt.Errorf("invalid point") + } + return p, nil +} + +// rhs of the curve equation +func rhsPallas(x *fp.Fp) *fp.Fp { + x2 := new(fp.Fp).Square(x) + x3 := new(fp.Fp).Mul(x, x2) + return new(fp.Fp).Add(x3, b) +} + +func (p Ep) CurveName() string { + return "pallas" +} + +func (p Ep) SumOfProducts(points []*Ep, scalars []Scalar) *Ep { + nScalars := make([]*big.Int, len(scalars)) + for i, s := range scalars { + sc, ok := s.(*ScalarPallas) + if !ok { + return nil + } + nScalars[i] = sc.value.BigInt() + } + return sumOfProductsPippengerPallas(points, nScalars) +} + +func (p *Ep) X() *fp.Fp { + t := new(Ep).Set(p) + t.toAffine() + return new(fp.Fp).Set(t.x) +} + +func (p *Ep) Y() *fp.Fp { + t := new(Ep).Set(p) + t.toAffine() + return new(fp.Fp).Set(t.y) +} + +func (p *Ep) IsOnCurve() bool { + // y^2 = x^3 + axz^4 + bz^6 + // a = 0 + // b = 5 + z2 := new(fp.Fp).Square(p.z) + z4 := new(fp.Fp).Square(z2) + z6 := new(fp.Fp).Mul(z2, z4) + x2 := new(fp.Fp).Square(p.x) + x3 := new(fp.Fp).Mul(x2, p.x) + + lhs := new(fp.Fp).Square(p.y) + rhs := new(fp.Fp).SetUint64(5) + rhs.Mul(rhs, z6) + rhs.Add(rhs, x3) + return p.z.IsZero() || lhs.Equal(rhs) +} + +func (p *Ep) CMove(lhs, rhs *Ep, condition int) *Ep { + p.x = new(fp.Fp).CMove(lhs.x, rhs.x, condition) + p.y = new(fp.Fp).CMove(lhs.y, rhs.y, condition) + p.z = new(fp.Fp).CMove(lhs.z, rhs.z, condition) + return p +} + +func sumOfProductsPippengerPallas(points []*Ep, scalars []*big.Int) *Ep { + if len(points) != len(scalars) { + return nil + } + + const w = 6 + + bucketSize := (1 << w) - 1 + windows := make([]*Ep, 255/w+1) + for i := range windows { + windows[i] = new(Ep).Identity() + } + bucket := make([]*Ep, bucketSize) + + for j := 0; j < len(windows); j++ { + for i := 0; i < bucketSize; i++ { + bucket[i] = new(Ep).Identity() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(w*j)).Int64()) + if index != 0 { + bucket[index-1].Add(bucket[index-1], points[i]) + } + } + + acc, sum := new(Ep).Identity(), new(Ep).Identity() + + for i := bucketSize - 1; i >= 0; i-- { + sum.Add(sum, bucket[i]) + acc.Add(acc, sum) + } + windows[j] = acc + } + + acc := new(Ep).Identity() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < w; j++ { + acc.Double(acc) + } + acc.Add(acc, windows[i]) + } + return acc +} + +// Implements a degree 3 isogeny map. +// The input and output are in Jacobian coordinates, using the method +// in "Avoiding inversions" [WB2019, section 4.3]. +func isoMap(p *Ep) *Ep { + var z [4]*fp.Fp + z[0] = new(fp.Fp).Square(p.z) //z^2 + z[1] = new(fp.Fp).Mul(z[0], p.z) // z^3 + z[2] = new(fp.Fp).Square(z[0]) // z^4 + z[3] = new(fp.Fp).Square(z[1]) // z^6 + + // ((iso[0] * x + iso[1] * z^2) * x + iso[2] * z^4) * x + iso[3] * z^6 + numX := new(fp.Fp).Set(isomapper[0]) + numX.Mul(numX, p.x) + numX.Add(numX, new(fp.Fp).Mul(isomapper[1], z[0])) + numX.Mul(numX, p.x) + numX.Add(numX, new(fp.Fp).Mul(isomapper[2], z[2])) + numX.Mul(numX, p.x) + numX.Add(numX, new(fp.Fp).Mul(isomapper[3], z[3])) + + // (z^2 * x + iso[4] * z^4) * x + iso[5] * z^6 + divX := new(fp.Fp).Set(z[0]) + divX.Mul(divX, p.x) + divX.Add(divX, new(fp.Fp).Mul(isomapper[4], z[2])) + divX.Mul(divX, p.x) + divX.Add(divX, new(fp.Fp).Mul(isomapper[5], z[3])) + + // (((iso[6] * x + iso[7] * z2) * x + iso[8] * z4) * x + iso[9] * z6) * y + numY := new(fp.Fp).Set(isomapper[6]) + numY.Mul(numY, p.x) + numY.Add(numY, new(fp.Fp).Mul(isomapper[7], z[0])) + numY.Mul(numY, p.x) + numY.Add(numY, new(fp.Fp).Mul(isomapper[8], z[2])) + numY.Mul(numY, p.x) + numY.Add(numY, new(fp.Fp).Mul(isomapper[9], z[3])) + numY.Mul(numY, p.y) + + // (((x + iso[10] * z2) * x + iso[11] * z4) * x + iso[12] * z6) * z3 + divY := new(fp.Fp).Set(p.x) + divY.Add(divY, new(fp.Fp).Mul(isomapper[10], z[0])) + divY.Mul(divY, p.x) + divY.Add(divY, new(fp.Fp).Mul(isomapper[11], z[2])) + divY.Mul(divY, p.x) + divY.Add(divY, new(fp.Fp).Mul(isomapper[12], z[3])) + divY.Mul(divY, z[1]) + + z0 := new(fp.Fp).Mul(divX, divY) + x := new(fp.Fp).Mul(numX, divY) + x.Mul(x, z0) + y := new(fp.Fp).Mul(numY, divX) + y.Mul(y, new(fp.Fp).Square(z0)) + + return &Ep{ + x, y, z0, + } +} + +func mapSswu(u *fp.Fp) *Ep { + //c1 := new(fp.Fp).Neg(isoa) + //c1.Invert(c1) + //c1.Mul(isob, c1) + c1 := &fp.Fp{ + 0x1ee770ce078456ec, + 0x48cfd64c2ce76be0, + 0x43d5774c0ab79e2f, + 0x23368d2bdce28cf3, + } + //c2 := new(fp.Fp).Neg(z) + //c2.Invert(c2) + c2 := &fp.Fp{ + 0x03df915f89d89d8a, + 0x8f1e8db09ef82653, + 0xd89d89d89d89d89d, + 0x1d89d89d89d89d89, + } + + u2 := new(fp.Fp).Square(u) + tv1 := new(fp.Fp).Mul(z, u2) + tv2 := new(fp.Fp).Square(tv1) + x1 := new(fp.Fp).Add(tv1, tv2) + x1.Invert(x1) + e1 := bool2int[x1.IsZero()] + x1.Add(x1, new(fp.Fp).SetOne()) + x1.CMove(x1, c2, e1) + x1.Mul(x1, c1) + gx1 := new(fp.Fp).Square(x1) + gx1.Add(gx1, isoa) + gx1.Mul(gx1, x1) + gx1.Add(gx1, isob) + x2 := new(fp.Fp).Mul(tv1, x1) + tv2.Mul(tv1, tv2) + gx2 := new(fp.Fp).Mul(gx1, tv2) + gx1Sqrt, e2 := new(fp.Fp).Sqrt(gx1) + x := new(fp.Fp).CMove(x2, x1, bool2int[e2]) + gx2Sqrt, _ := new(fp.Fp).Sqrt(gx2) + y := new(fp.Fp).CMove(gx2Sqrt, gx1Sqrt, bool2int[e2]) + e3 := u.IsOdd() == y.IsOdd() + y.CMove(new(fp.Fp).Neg(y), y, bool2int[e3]) + + return &Ep{ + x: x, y: y, z: new(fp.Fp).SetOne(), + } +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/hash.go b/vendor/github.com/coinbase/kryptology/pkg/core/hash.go new file mode 100644 index 0000000000..415be8a03b --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/hash.go @@ -0,0 +1,272 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package core + +import ( + "bytes" + "crypto/elliptic" + "crypto/sha256" + "fmt" + "hash" + "math" + "math/big" + + "github.com/btcsuite/btcd/btcec" + "golang.org/x/crypto/hkdf" + + "github.com/coinbase/kryptology/internal" +) + +type HashField struct { + // F_p^k + Order *big.Int // p^k + Characteristic *big.Int // p + ExtensionDegree *big.Int // k +} + +type Params struct { + F *HashField + SecurityParameter int + Hash func() hash.Hash + L int +} + +func getParams(curve elliptic.Curve) (*Params, error) { + switch curve.Params().Name { + case btcec.S256().Name, elliptic.P256().Params().Name: + return &Params{ + F: &HashField{ + Order: curve.Params().P, + Characteristic: curve.Params().P, + ExtensionDegree: new(big.Int).SetInt64(1), + }, + SecurityParameter: 128, + Hash: sha256.New, + L: 48, + }, nil + case "Bls12381G1": + return &Params{ + F: &HashField{ + Order: curve.Params().P, + Characteristic: curve.Params().P, + ExtensionDegree: new(big.Int).SetInt64(1), + }, + SecurityParameter: 128, + Hash: sha256.New, + L: 48, + }, nil + case "ed25519": + return &Params{ + F: &HashField{ + Order: curve.Params().P, + Characteristic: curve.Params().P, + ExtensionDegree: new(big.Int).SetInt64(1), + }, + SecurityParameter: 128, + Hash: sha256.New, + L: 48, + }, nil + default: + return nil, fmt.Errorf("Not implemented: %s", curve.Params().Name) + } +} + +func I2OSP(b, n int) []byte { + os := new(big.Int).SetInt64(int64(b)).Bytes() + if n > len(os) { + var buf bytes.Buffer + buf.Write(make([]byte, n-len(os))) + buf.Write(os) + return buf.Bytes() + } + return os[:n] +} + +func OS2IP(os []byte) *big.Int { + return new(big.Int).SetBytes(os) +} + +func hashThis(f func() hash.Hash, this []byte) ([]byte, error) { + h := f() + w, err := h.Write(this) + if w != len(this) { + return nil, fmt.Errorf("bytes written to hash doesn't match expected") + } else if err != nil { + return nil, err + } + v := h.Sum(nil) + return v, nil +} + +func concat(xs ...[]byte) []byte { + var result []byte + for _, x := range xs { + result = append(result, x...) + } + return result +} + +func xor(b1, b2 []byte) []byte { + // b1 and b2 must be same length + result := make([]byte, len(b1)) + for i := range b1 { + result[i] = b1[i] ^ b2[i] + } + + return result +} + +func ExpandMessageXmd(f func() hash.Hash, msg, DST []byte, lenInBytes int) ([]byte, error) { + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-5.4.1 + + // step 1 + ell := int(math.Ceil(float64(lenInBytes) / float64(f().Size()))) + + //step 2 + if ell > 255 { + return nil, fmt.Errorf("ell > 255") + } + + // step 3 + dstPrime := append(DST, I2OSP(len(DST), 1)...) + + // step 4 + zPad := I2OSP(0, f().BlockSize()) + + // step 5 & 6 + msgPrime := concat(zPad, msg, I2OSP(lenInBytes, 2), I2OSP(0, 1), dstPrime) + + var err error + + b := make([][]byte, ell+1) + + // step 7 + b[0], err = hashThis(f, msgPrime) + if err != nil { + return nil, err + } + + // step 8 + b[1], err = hashThis(f, concat(b[0], I2OSP(1, 1), dstPrime)) + if err != nil { + return nil, err + } + + // step 9 + for i := 2; i <= ell; i++ { + // step 10 + b[i], err = hashThis(f, concat(xor(b[0], b[i-1]), I2OSP(i, 1), dstPrime)) + if err != nil { + return nil, err + } + } + // step 11 + uniformBytes := concat(b[1:]...) + + // step 12 + return uniformBytes[:lenInBytes], nil +} + +func hashToField(msg []byte, count int, curve elliptic.Curve) ([][]*big.Int, error) { + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-5.3 + + parameters, err := getParams(curve) + if err != nil { + return nil, err + } + + f := parameters.Hash + + DST := []byte("Coinbase_tECDSA") + + m := int(parameters.F.ExtensionDegree.Int64()) + L := parameters.L + + // step 1 + lenInBytes := count * m * L + + // step 2 + uniformBytes, err := ExpandMessageXmd(f, msg, DST, lenInBytes) + if err != nil { + return nil, err + } + + u := make([][]*big.Int, count) + + // step 3 + for i := 0; i < count; i++ { + e := make([]*big.Int, m) + // step 4 + for j := 0; j < m; j++ { + // step 5 + elmOffset := L * (j + i*m) + // step 6 + tv := uniformBytes[elmOffset : elmOffset+L] + // step 7 + e[j] = new(big.Int).Mod(OS2IP(tv), parameters.F.Characteristic) + + } + // step 8 + u[i] = e + } + // step 9 + return u, nil +} + +func Hash(msg []byte, curve elliptic.Curve) (*big.Int, error) { + u, err := hashToField(msg, 1, curve) + if err != nil { + return nil, err + } + return u[0][0], nil +} + +// fiatShamir computes the HKDF over many values +// iteratively such that each value is hashed separately +// and based on preceding values +// +// The first value is computed as okm_0 = KDF(f || value) where +// f is a byte slice of 32 0xFF +// salt is zero-filled byte slice with length equal to the hash output length +// info is the protocol name +// okm is the 32 byte output +// +// The each subsequent iteration is computed by as okm_i = KDF(f_i || value || okm_{i-1}) +// where f_i = 2^b - 1 - i such that there are 0xFF bytes prior to the value. +// f_1 changes the first byte to 0xFE, f_2 to 0xFD. The previous okm is appended to the value +// to provide cryptographic domain separation. +// See https://signal.org/docs/specifications/x3dh/#cryptographic-notation +// and https://signal.org/docs/specifications/xeddsa/#hash-functions +// for more details. +// This uses the KDF function similar to X3DH for each `value` +// But changes the key just like XEdDSA where the prefix bytes change by a single bit +func FiatShamir(values ...*big.Int) ([]byte, error) { + // Don't accept any nil arguments + if AnyNil(values...) { + return nil, internal.ErrNilArguments + } + + info := []byte("Coinbase tECDSA 1.0") + salt := make([]byte, 32) + okm := make([]byte, 32) + f := bytes.Repeat([]byte{0xFF}, 32) + + for _, b := range values { + ikm := append(f, b.Bytes()...) + ikm = append(ikm, okm...) + kdf := hkdf.New(sha256.New, ikm, salt, info) + n, err := kdf.Read(okm) + if err != nil { + return nil, err + } + if n != len(okm) { + return nil, fmt.Errorf("unable to read expected number of bytes want=%v got=%v", len(okm), n) + } + internal.ByteSub(f) + } + return okm, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/mod.go b/vendor/github.com/coinbase/kryptology/pkg/core/mod.go new file mode 100644 index 0000000000..503ea4ed29 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/mod.go @@ -0,0 +1,178 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Package core contains convenience functions for modular arithmetic. + +// Package core contains a set of primitives, including but not limited to various +// elliptic curves, hashes, and commitment schemes. These primitives are used internally +// and can also be used independently on their own externally. +package core + +import ( + crand "crypto/rand" + "crypto/subtle" + "fmt" + "math/big" + + "github.com/coinbase/kryptology/internal" +) + +var ( + // Zero is additive identity in the set of integers + Zero = big.NewInt(0) + + // One is the multiplicative identity in the set of integers + One = big.NewInt(1) + + // Two is the odd prime + Two = big.NewInt(2) +) + +// ConstantTimeEqByte determines if a, b have identical byte serialization +// and signs. It uses the crypto/subtle package to get a constant time comparison +// over byte representations. Return value is a byte which may be +// useful in bitwise operations. Returns 0x1 if the two values have the +// identical sign and byte representation; 0x0 otherwise. +func ConstantTimeEqByte(a, b *big.Int) byte { + if a == nil && a == b { + return 1 + } + if a == nil || b == nil { + return 0 + } + // Determine if the byte representations are the same + var sameBytes byte + if subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1 { + sameBytes = 1 + } else { + sameBytes = 0 + } + + // Determine if the signs are the same + var sameSign byte + if a.Sign() == b.Sign() { + sameSign = 1 + } else { + sameSign = 0 + } + + // Report the conjunction + return sameBytes & sameSign +} + +// ConstantTimeEq determines if a, b have identical byte serialization +// and uses the crypto/subtle package to get a constant time comparison +// over byte representations. +func ConstantTimeEq(a, b *big.Int) bool { + return ConstantTimeEqByte(a, b) == 1 +} + +// In determines ring membership before modular reduction: x ∈ Z_m +// returns nil if 0 ≤ x < m +func In(x, m *big.Int) error { + if AnyNil(x, m) { + return internal.ErrNilArguments + } + // subtle doesn't support constant time big.Int compare + // just use big.Cmp for now + // x ∈ Z_m ⇔ 0 ≤ x < m + if x.Cmp(Zero) != -1 && x.Cmp(m) == -1 { + return nil + } + return internal.ErrZmMembership +} + +// Add (modular addition): z = x+y (modulo m) +func Add(x, y, m *big.Int) (*big.Int, error) { + if AnyNil(x, y) { + return nil, internal.ErrNilArguments + } + z := new(big.Int).Add(x, y) + // Compute the residue if one is specified, otherwise + // we leave the value as an unbound integer + if m != nil { + z.Mod(z, m) + } + return z, nil +} + +// Mul (modular multiplication): z = x*y (modulo m) +func Mul(x, y, m *big.Int) (*big.Int, error) { + if AnyNil(x, y) { + return nil, internal.ErrNilArguments + } + z := new(big.Int).Mul(x, y) + + // Compute the residue if one is specified, otherwise + // we leave the value as an unbound integer + if m != nil { + z.Mod(z, m) + } + return z, nil +} + +// Exp (modular exponentiation): z = x^y (modulo m) +func Exp(x, y, m *big.Int) (*big.Int, error) { + if AnyNil(x, y) { + return nil, internal.ErrNilArguments + } + // This wrapper looks silly, but it makes the calling code read more consistently. + return new(big.Int).Exp(x, y, m), nil +} + +// Neg (modular negation): z = -x (modulo m) +func Neg(x, m *big.Int) (*big.Int, error) { + if AnyNil(x, m) { + return nil, internal.ErrNilArguments + } + z := new(big.Int).Neg(x) + z.Mod(z, m) + return z, nil +} + +// Inv (modular inverse): returns y such that xy = 1 (modulo m). +func Inv(x, m *big.Int) (*big.Int, error) { + if AnyNil(x, m) { + return nil, internal.ErrNilArguments + } + z := new(big.Int).ModInverse(x, m) + if z == nil { + return nil, fmt.Errorf("cannot compute the multiplicative inverse") + } + return z, nil +} + +// Rand generates a cryptographically secure random integer in the range: 1 < r < m. +func Rand(m *big.Int) (*big.Int, error) { + if m == nil { + return nil, internal.ErrNilArguments + } + + // Select a random element, but not zero or one + // The reason is the random element may be used as a Scalar or an exponent. + // An exponent of 1 is generally acceptable because the generator can't be + // 1. If a Scalar is combined with another Scalar like in fiat-shamir, it + // offers no hiding properties when multiplied. + for { + result, err := crand.Int(crand.Reader, m) + if err != nil { + return nil, err + } + + if result.Cmp(One) == 1 { // result > 1 + return result, nil + } + } +} + +// AnyNil determines if any of values are nil +func AnyNil(values ...*big.Int) bool { + for _, x := range values { + if x == nil { + return true + } + } + return false +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/core/primes.go b/vendor/github.com/coinbase/kryptology/pkg/core/primes.go new file mode 100644 index 0000000000..24ae766edb --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/core/primes.go @@ -0,0 +1,42 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package core + +import ( + "crypto/rand" + "fmt" + "math" + "math/big" +) + +// GenerateSafePrime creates a prime number `p` +// where (`p`-1)/2 is also prime with at least `bits` +func GenerateSafePrime(bits uint) (*big.Int, error) { + if bits < 3 { + return nil, fmt.Errorf("safe prime size must be at least 3-bits") + } + + var p *big.Int + var err error + checks := int(math.Max(float64(bits)/16, 8)) + for { + // rand.Prime throws an error if bits < 2 + // -1 so the Sophie-Germain prime is 1023 bits + // and the Safe prime is 1024 + p, err = rand.Prime(rand.Reader, int(bits)-1) + if err != nil { + return nil, err + } + p.Add(p.Lsh(p, 1), One) + + if p.ProbablyPrime(checks) { + break + } + } + + return p, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/sharing/README.md b/vendor/github.com/coinbase/kryptology/pkg/sharing/README.md new file mode 100644 index 0000000000..3ca33831d2 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/sharing/README.md @@ -0,0 +1,7 @@ +# Shamir Secret Sharing Scheme + +The code is an implementation of the following papers. + +- https://dl.acm.org/doi/pdf/10.1145/359168.359176 +- https://www.cs.umd.edu/~gasarch/TOPICS/secretsharing/feldmanVSS.pdf +- https://link.springer.com/content/pdf/10.1007%2F3-540-46766-1_9.pdf \ No newline at end of file diff --git a/vendor/github.com/coinbase/kryptology/pkg/sharing/feldman.go b/vendor/github.com/coinbase/kryptology/pkg/sharing/feldman.go new file mode 100644 index 0000000000..313cd4cc73 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/sharing/feldman.go @@ -0,0 +1,112 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package sharing + +import ( + "fmt" + "io" + + "github.com/coinbase/kryptology/pkg/core/curves" +) + +type FeldmanVerifier struct { + Commitments []curves.Point +} + +func (v FeldmanVerifier) Verify(share *ShamirShare) error { + curve := curves.GetCurveByName(v.Commitments[0].CurveName()) + err := share.Validate(curve) + if err != nil { + return err + } + x := curve.Scalar.New(int(share.Id)) + i := curve.Scalar.One() + rhs := v.Commitments[0] + + for j := 1; j < len(v.Commitments); j++ { + i = i.Mul(x) + rhs = rhs.Add(v.Commitments[j].Mul(i)) + } + sc, _ := curve.Scalar.SetBytes(share.Value) + lhs := v.Commitments[0].Generator().Mul(sc) + + if lhs.Equal(rhs) { + return nil + } else { + return fmt.Errorf("not equal") + } +} + +type Feldman struct { + Threshold, Limit uint32 + Curve *curves.Curve +} + +func NewFeldman(threshold, limit uint32, curve *curves.Curve) (*Feldman, error) { + if limit < threshold { + return nil, fmt.Errorf("limit cannot be less than threshold") + } + if threshold < 2 { + return nil, fmt.Errorf("threshold cannot be less than 2") + } + if limit > 255 { + return nil, fmt.Errorf("cannot exceed 255 shares") + } + if curve == nil { + return nil, fmt.Errorf("invalid curve") + } + return &Feldman{threshold, limit, curve}, nil +} + +func (f Feldman) Split(secret curves.Scalar, reader io.Reader) (*FeldmanVerifier, []*ShamirShare, error) { + if secret.IsZero() { + return nil, nil, fmt.Errorf("invalid secret") + } + shamir := &Shamir{ + threshold: f.Threshold, + limit: f.Limit, + curve: f.Curve, + } + shares, poly := shamir.getPolyAndShares(secret, reader) + verifier := new(FeldmanVerifier) + verifier.Commitments = make([]curves.Point, f.Threshold) + for i := range verifier.Commitments { + verifier.Commitments[i] = f.Curve.ScalarBaseMult(poly.Coefficients[i]) + } + return verifier, shares, nil +} + +func (f Feldman) LagrangeCoeffs(shares map[uint32]*ShamirShare) (map[uint32]curves.Scalar, error) { + shamir := &Shamir{ + threshold: f.Threshold, + limit: f.Limit, + curve: f.Curve, + } + identities := make([]uint32, 0) + for _, xi := range shares { + identities = append(identities, xi.Id) + } + return shamir.LagrangeCoeffs(identities) +} + +func (f Feldman) Combine(shares ...*ShamirShare) (curves.Scalar, error) { + shamir := &Shamir{ + threshold: f.Threshold, + limit: f.Limit, + curve: f.Curve, + } + return shamir.Combine(shares...) +} + +func (f Feldman) CombinePoints(shares ...*ShamirShare) (curves.Point, error) { + shamir := &Shamir{ + threshold: f.Threshold, + limit: f.Limit, + curve: f.Curve, + } + return shamir.CombinePoints(shares...) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/sharing/pedersen.go b/vendor/github.com/coinbase/kryptology/pkg/sharing/pedersen.go new file mode 100644 index 0000000000..904f372ab9 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/sharing/pedersen.go @@ -0,0 +1,152 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package sharing + +import ( + "fmt" + "io" + + "github.com/coinbase/kryptology/pkg/core/curves" +) + +// Pedersen Verifiable Secret Sharing Scheme +type Pedersen struct { + threshold, limit uint32 + curve *curves.Curve + generator curves.Point +} + +type PedersenVerifier struct { + Generator curves.Point + Commitments []curves.Point +} + +func (pv PedersenVerifier) Verify(share, blindShare *ShamirShare) error { + curve := curves.GetCurveByName(pv.Generator.CurveName()) + if err := share.Validate(curve); err != nil { + return err + } + if err := blindShare.Validate(curve); err != nil { + return err + } + + x := curve.Scalar.New(int(share.Id)) + i := curve.Scalar.One() + rhs := pv.Commitments[0] + + for j := 1; j < len(pv.Commitments); j++ { + i = i.Mul(x) + rhs = rhs.Add(pv.Commitments[j].Mul(i)) + } + + sc, _ := curve.Scalar.SetBytes(share.Value) + bsc, _ := curve.Scalar.SetBytes(blindShare.Value) + g := pv.Commitments[0].Generator().Mul(sc) + h := pv.Generator.Mul(bsc) + lhs := g.Add(h) + + if lhs.Equal(rhs) { + return nil + } else { + return fmt.Errorf("not equal") + } +} + +// PedersenResult contains all the data from calling Split +type PedersenResult struct { + Blinding curves.Scalar + BlindingShares, SecretShares []*ShamirShare + FeldmanVerifier *FeldmanVerifier + PedersenVerifier *PedersenVerifier +} + +// NewPedersen creates a new pedersen VSS +func NewPedersen(threshold, limit uint32, generator curves.Point) (*Pedersen, error) { + if limit < threshold { + return nil, fmt.Errorf("limit cannot be less than threshold") + } + if threshold < 2 { + return nil, fmt.Errorf("threshold cannot be less than 2") + } + if limit > 255 { + return nil, fmt.Errorf("cannot exceed 255 shares") + } + curve := curves.GetCurveByName(generator.CurveName()) + if curve == nil { + return nil, fmt.Errorf("invalid curve") + } + if generator == nil { + return nil, fmt.Errorf("invalid generator") + } + if !generator.IsOnCurve() || generator.IsIdentity() { + return nil, fmt.Errorf("invalid generator") + } + return &Pedersen{threshold, limit, curve, generator}, nil +} + +// Split creates the verifiers, blinding and shares +func (pd Pedersen) Split(secret curves.Scalar, reader io.Reader) (*PedersenResult, error) { + // generate a random blinding factor + blinding := pd.curve.Scalar.Random(reader) + + shamir := Shamir{pd.threshold, pd.limit, pd.curve} + // split the secret into shares + shares, poly := shamir.getPolyAndShares(secret, reader) + + // split the blinding into shares + blindingShares, polyBlinding := shamir.getPolyAndShares(blinding, reader) + + // Generate the verifiable commitments to the polynomial for the shares + blindedverifiers := make([]curves.Point, pd.threshold) + verifiers := make([]curves.Point, pd.threshold) + + // ({p0 * G + b0 * H}, ...,{pt * G + bt * H}) + for i, c := range poly.Coefficients { + s := pd.curve.ScalarBaseMult(c) + b := pd.generator.Mul(polyBlinding.Coefficients[i]) + bv := s.Add(b) + blindedverifiers[i] = bv + verifiers[i] = s + } + verifier1 := &FeldmanVerifier{Commitments: verifiers} + verifier2 := &PedersenVerifier{Commitments: blindedverifiers, Generator: pd.generator} + + return &PedersenResult{ + blinding, blindingShares, shares, verifier1, verifier2, + }, nil +} + +func (pd Pedersen) LagrangeCoeffs(shares map[uint32]*ShamirShare) (map[uint32]curves.Scalar, error) { + shamir := &Shamir{ + threshold: pd.threshold, + limit: pd.limit, + curve: pd.curve, + } + identities := make([]uint32, 0) + for _, xi := range shares { + identities = append(identities, xi.Id) + } + return shamir.LagrangeCoeffs(identities) +} + +func (pd Pedersen) Combine(shares ...*ShamirShare) (curves.Scalar, error) { + shamir := &Shamir{ + threshold: pd.threshold, + limit: pd.limit, + curve: pd.curve, + } + return shamir.Combine(shares...) +} + +func (pd Pedersen) CombinePoints(shares ...*ShamirShare) (curves.Point, error) { + shamir := &Shamir{ + threshold: pd.threshold, + limit: pd.limit, + curve: pd.curve, + } + return shamir.CombinePoints(shares...) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/sharing/polynomial.go b/vendor/github.com/coinbase/kryptology/pkg/sharing/polynomial.go new file mode 100644 index 0000000000..7b424257d2 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/sharing/polynomial.go @@ -0,0 +1,35 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package sharing + +import ( + "io" + + "github.com/coinbase/kryptology/pkg/core/curves" +) + +type Polynomial struct { + Coefficients []curves.Scalar +} + +func (p *Polynomial) Init(intercept curves.Scalar, degree uint32, reader io.Reader) *Polynomial { + p.Coefficients = make([]curves.Scalar, degree) + p.Coefficients[0] = intercept.Clone() + for i := 1; i < int(degree); i++ { + p.Coefficients[i] = intercept.Random(reader) + } + return p +} + +func (p Polynomial) Evaluate(x curves.Scalar) curves.Scalar { + degree := len(p.Coefficients) - 1 + out := p.Coefficients[degree].Clone() + for i := degree - 1; i >= 0; i-- { + out = out.Mul(x).Add(p.Coefficients[i]) + } + return out +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/sharing/shamir.go b/vendor/github.com/coinbase/kryptology/pkg/sharing/shamir.go new file mode 100644 index 0000000000..1925db731f --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/sharing/shamir.go @@ -0,0 +1,206 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Package sharing is an implementation of shamir secret sharing and implements the following papers. +// +// - https://dl.acm.org/doi/pdf/10.1145/359168.359176 +// - https://www.cs.umd.edu/~gasarch/TOPICS/secretsharing/feldmanVSS.pdf +// - https://link.springer.com/content/pdf/10.1007%2F3-540-46766-1_9.pdf +package sharing + +import ( + "encoding/binary" + "fmt" + "io" + + "github.com/coinbase/kryptology/pkg/core/curves" +) + +type ShamirShare struct { + Id uint32 `json:"identifier"` + Value []byte `json:"value"` +} + +func (ss ShamirShare) Validate(curve *curves.Curve) error { + if ss.Id == 0 { + return fmt.Errorf("invalid identifier") + } + sc, err := curve.Scalar.SetBytes(ss.Value) + if err != nil { + return err + } + if sc.IsZero() { + return fmt.Errorf("invalid share") + } + return nil +} + +func (ss ShamirShare) Bytes() []byte { + var id [4]byte + binary.BigEndian.PutUint32(id[:], ss.Id) + return append(id[:], ss.Value...) +} + +type Shamir struct { + threshold, limit uint32 + curve *curves.Curve +} + +func NewShamir(threshold, limit uint32, curve *curves.Curve) (*Shamir, error) { + if limit < threshold { + return nil, fmt.Errorf("limit cannot be less than threshold") + } + if threshold < 2 { + return nil, fmt.Errorf("threshold cannot be less than 2") + } + if limit > 255 { + return nil, fmt.Errorf("cannot exceed 255 shares") + } + if curve == nil { + return nil, fmt.Errorf("invalid curve") + } + return &Shamir{threshold, limit, curve}, nil +} + +func (s Shamir) Split(secret curves.Scalar, reader io.Reader) ([]*ShamirShare, error) { + if secret.IsZero() { + return nil, fmt.Errorf("invalid secret") + } + shares, _ := s.getPolyAndShares(secret, reader) + return shares, nil +} + +func (s Shamir) getPolyAndShares(secret curves.Scalar, reader io.Reader) ([]*ShamirShare, *Polynomial) { + poly := new(Polynomial).Init(secret, s.threshold, reader) + shares := make([]*ShamirShare, s.limit) + for i := range shares { + x := s.curve.Scalar.New(i + 1) + shares[i] = &ShamirShare{ + Id: uint32(i + 1), + Value: poly.Evaluate(x).Bytes(), + } + } + return shares, poly +} + +func (s Shamir) LagrangeCoeffs(identities []uint32) (map[uint32]curves.Scalar, error) { + xs := make(map[uint32]curves.Scalar, len(identities)) + for _, xi := range identities { + xs[xi] = s.curve.Scalar.New(int(xi)) + } + + result := make(map[uint32]curves.Scalar, len(identities)) + for i, xi := range xs { + num := s.curve.Scalar.One() + den := s.curve.Scalar.One() + for j, xj := range xs { + if i == j { + continue + } + + num = num.Mul(xj) + den = den.Mul(xj.Sub(xi)) + } + if den.IsZero() { + return nil, fmt.Errorf("divide by zero") + } + result[i] = num.Div(den) + } + return result, nil +} + +func (s Shamir) Combine(shares ...*ShamirShare) (curves.Scalar, error) { + if len(shares) < int(s.threshold) { + return nil, fmt.Errorf("invalid number of shares") + } + dups := make(map[uint32]bool, len(shares)) + xs := make([]curves.Scalar, len(shares)) + ys := make([]curves.Scalar, len(shares)) + + for i, share := range shares { + err := share.Validate(s.curve) + if err != nil { + return nil, err + } + if share.Id > s.limit { + return nil, fmt.Errorf("invalid share identifier") + } + if _, in := dups[share.Id]; in { + return nil, fmt.Errorf("duplicate share") + } + dups[share.Id] = true + ys[i], _ = s.curve.Scalar.SetBytes(share.Value) + xs[i] = s.curve.Scalar.New(int(share.Id)) + } + return s.interpolate(xs, ys) +} + +func (s Shamir) CombinePoints(shares ...*ShamirShare) (curves.Point, error) { + if len(shares) < int(s.threshold) { + return nil, fmt.Errorf("invalid number of shares") + } + dups := make(map[uint32]bool, len(shares)) + xs := make([]curves.Scalar, len(shares)) + ys := make([]curves.Point, len(shares)) + + for i, share := range shares { + err := share.Validate(s.curve) + if err != nil { + return nil, err + } + if share.Id > s.limit { + return nil, fmt.Errorf("invalid share identifier") + } + if _, in := dups[share.Id]; in { + return nil, fmt.Errorf("duplicate share") + } + dups[share.Id] = true + sc, _ := s.curve.Scalar.SetBytes(share.Value) + ys[i] = s.curve.ScalarBaseMult(sc) + xs[i] = s.curve.Scalar.New(int(share.Id)) + } + return s.interpolatePoint(xs, ys) +} + +func (s Shamir) interpolate(xs, ys []curves.Scalar) (curves.Scalar, error) { + result := s.curve.Scalar.Zero() + for i, xi := range xs { + num := s.curve.Scalar.One() + den := s.curve.Scalar.One() + for j, xj := range xs { + if i == j { + continue + } + num = num.Mul(xj) + den = den.Mul(xj.Sub(xi)) + } + if den.IsZero() { + return nil, fmt.Errorf("divide by zero") + } + result = result.Add(ys[i].Mul(num.Div(den))) + } + return result, nil +} + +func (s Shamir) interpolatePoint(xs []curves.Scalar, ys []curves.Point) (curves.Point, error) { + result := s.curve.NewIdentityPoint() + for i, xi := range xs { + num := s.curve.Scalar.One() + den := s.curve.Scalar.One() + for j, xj := range xs { + if i == j { + continue + } + num = num.Mul(xj) + den = den.Mul(xj.Sub(xi)) + } + if den.IsZero() { + return nil, fmt.Errorf("divide by zero") + } + result = result.Add(ys[i].Mul(num.Div(den))) + } + return result, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/lib.go b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/lib.go new file mode 100644 index 0000000000..dd2004f908 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/lib.go @@ -0,0 +1,207 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Package bls_sig is an implementation of the BLS signature defined in https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +package bls_sig + +import ( + "crypto/rand" + "crypto/sha256" + "crypto/subtle" + "fmt" + + "golang.org/x/crypto/hkdf" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" + "github.com/coinbase/kryptology/pkg/sharing" +) + +// Secret key in Fr +const SecretKeySize = 32 + +// Secret key share with identifier byte in Fr +const SecretKeyShareSize = 33 + +// The salt used with generating secret keys +// See section 2.3 from https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +const hkdfKeyGenSalt = "BLS-SIG-KEYGEN-SALT-" + +// Represents a value mod r where r is the curve order or +// order of the subgroups in G1 and G2 +type SecretKey struct { + value *native.Field +} + +func allRowsUnique(data [][]byte) bool { + seen := make(map[string]bool) + for _, row := range data { + m := string(row) + if _, ok := seen[m]; ok { + return false + } + seen[m] = true + } + return true +} + +func generateRandBytes(count int) ([]byte, error) { + ikm := make([]byte, count) + cnt, err := rand.Read(ikm) + if err != nil { + return nil, err + } + if cnt != count { + return nil, fmt.Errorf("unable to read sufficient random data") + } + return ikm, nil +} + +// Creates a new BLS secret key +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (sk SecretKey) Generate(ikm []byte) (*SecretKey, error) { + if len(ikm) < 32 { + return nil, fmt.Errorf("ikm is too short. Must be at least 32") + } + + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-2.3 + h := sha256.New() + n, err := h.Write([]byte(hkdfKeyGenSalt)) + if err != nil { + return nil, err + } + if n != len(hkdfKeyGenSalt) { + return nil, fmt.Errorf("incorrect salt bytes written to be hashed") + } + salt := h.Sum(nil) + + ikm = append(ikm, 0) + // Leaves key_info parameter as the default empty string + // and just adds parameter I2OSP(L, 2) + var okm [native.WideFieldBytes]byte + kdf := hkdf.New(sha256.New, ikm, salt, []byte{0, 48}) + read, err := kdf.Read(okm[:48]) + copy(okm[:48], internal.ReverseScalarBytes(okm[:48])) + if err != nil { + return nil, err + } + if read != 48 { + return nil, fmt.Errorf("failed to create private key") + } + v := bls12381.Bls12381FqNew().SetBytesWide(&okm) + return &SecretKey{value: v}, nil +} + +// Serialize a secret key to raw bytes +func (sk SecretKey) MarshalBinary() ([]byte, error) { + bytes := sk.value.Bytes() + return internal.ReverseScalarBytes(bytes[:]), nil +} + +// Deserialize a secret key from raw bytes +// Cannot be zero. Must be 32 bytes and cannot be all zeroes. +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-2.3 +func (sk *SecretKey) UnmarshalBinary(data []byte) error { + if len(data) != SecretKeySize { + return fmt.Errorf("secret key must be %d bytes", SecretKeySize) + } + zeros := make([]byte, len(data)) + if subtle.ConstantTimeCompare(data, zeros) == 1 { + return fmt.Errorf("secret key cannot be zero") + } + var bb [native.FieldBytes]byte + copy(bb[:], internal.ReverseScalarBytes(data)) + value, err := bls12381.Bls12381FqNew().SetBytes(&bb) + if err != nil { + return err + } + sk.value = value + return nil +} + +// SecretKeyShare is shamir share of a private key +type SecretKeyShare struct { + identifier byte + value []byte +} + +// Serialize a secret key share to raw bytes +func (sks SecretKeyShare) MarshalBinary() ([]byte, error) { + var blob [SecretKeyShareSize]byte + l := len(sks.value) + copy(blob[:l], sks.value) + blob[l] = sks.identifier + return blob[:], nil +} + +// Deserialize a secret key share from raw bytes +func (sks *SecretKeyShare) UnmarshalBinary(data []byte) error { + if len(data) != SecretKeyShareSize { + return fmt.Errorf("secret key share must be %d bytes", SecretKeyShareSize) + } + + zeros := make([]byte, len(data)) + if subtle.ConstantTimeCompare(data, zeros) == 1 { + return fmt.Errorf("secret key share cannot be zero") + } + l := len(data) + sks.identifier = data[l-1] + copy(sks.value, data[:l]) + return nil +} + +// thresholdizeSecretKey splits a composite secret key such that +// `threshold` partial signatures can be combined to form a composite signature +func thresholdizeSecretKey(secretKey *SecretKey, threshold, total uint) ([]*SecretKeyShare, error) { + // Verify our parameters are acceptable. + if secretKey == nil { + return nil, fmt.Errorf("secret key is nil") + } + if threshold > total { + return nil, fmt.Errorf("threshold cannot be greater than the total") + } + if threshold == 0 { + return nil, fmt.Errorf("threshold cannot be zero") + } + if total <= 1 { + return nil, fmt.Errorf("total must be larger than 1") + } + if total > 255 || threshold > 255 { + return nil, fmt.Errorf("cannot have more than 255 shares") + } + + curve := curves.BLS12381G1() + sss, err := sharing.NewShamir(uint32(threshold), uint32(total), curve) + if err != nil { + return nil, err + } + secret, ok := curve.NewScalar().(*curves.ScalarBls12381) + if !ok { + return nil, fmt.Errorf("invalid curve") + } + secret.Value = secretKey.value + shares, err := sss.Split(secret, rand.Reader) + if err != nil { + return nil, err + } + // Verify we got the expected number of shares + if uint(len(shares)) != total { + return nil, fmt.Errorf("%v != %v shares", len(shares), total) + } + + // Package our shares + secrets := make([]*SecretKeyShare, len(shares)) + for i, s := range shares { + // users expect BigEndian + sks := &SecretKeyShare{identifier: byte(s.Id), value: s.Value} + secrets[i] = sks + } + + return secrets, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls.go b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls.go new file mode 100644 index 0000000000..ae426a6e8b --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls.go @@ -0,0 +1,438 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package bls_sig + +import ( + "fmt" +) + +const ( + // Domain separation tag for basic signatures + // according to section 4.2.1 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignatureBasicVtDst = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_" + // Domain separation tag for basic signatures + // according to section 4.2.2 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignatureAugVtDst = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_" + // Domain separation tag for proof of possession signatures + // according to section 4.2.3 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignaturePopVtDst = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_" + // Domain separation tag for proof of possession proofs + // according to section 4.2.3 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsPopProofVtDst = "BLS_POP_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_" +) + +type BlsSchemeVt interface { + Keygen() (*PublicKeyVt, *SecretKey, error) + KeygenWithSeed(ikm []byte) (*PublicKeyVt, *SecretKey, error) + Sign(sk *SecretKey, msg []byte) (*SignatureVt, error) + Verify(pk *PublicKeyVt, msg []byte, sig *SignatureVt) bool + AggregateVerify(pks []*PublicKeyVt, msgs [][]byte, sigs []*SignatureVt) bool +} + +// generateKeysVt creates 32 bytes of random data to be fed to +// generateKeysWithSeedVt +func generateKeysVt() (*PublicKeyVt, *SecretKey, error) { + ikm, err := generateRandBytes(32) + if err != nil { + return nil, nil, err + } + return generateKeysWithSeedVt(ikm) +} + +// generateKeysWithSeedVt generates a BLS key pair given input key material (ikm) +func generateKeysWithSeedVt(ikm []byte) (*PublicKeyVt, *SecretKey, error) { + sk, err := new(SecretKey).Generate(ikm) + if err != nil { + return nil, nil, err + } + pk, err := sk.GetPublicKeyVt() + if err != nil { + return nil, nil, err + } + return pk, sk, nil +} + +// thresholdGenerateKeys will generate random secret key shares and the corresponding public key +func thresholdGenerateKeysVt(threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + pk, sk, err := generateKeysVt() + if err != nil { + return nil, nil, err + } + shares, err := thresholdizeSecretKey(sk, threshold, total) + if err != nil { + return nil, nil, err + } + return pk, shares, nil +} + +// thresholdGenerateKeysWithSeed will generate random secret key shares and the corresponding public key +// using the corresponding seed `ikm` +func thresholdGenerateKeysWithSeedVt(ikm []byte, threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + pk, sk, err := generateKeysWithSeedVt(ikm) + if err != nil { + return nil, nil, err + } + shares, err := thresholdizeSecretKey(sk, threshold, total) + if err != nil { + return nil, nil, err + } + return pk, shares, nil +} + +// SigBasic is minimal-pubkey-size scheme that doesn't support FastAggregateVerification. +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.1 +type SigBasicVt struct { + dst string +} + +// Creates a new BLS basic signature scheme with the standard domain separation tag used for signatures. +func NewSigBasicVt() *SigBasicVt { + return &SigBasicVt{dst: blsSignatureBasicVtDst} +} + +// Creates a new BLS basic signature scheme with a custom domain separation tag used for signatures. +func NewSigBasicVtWithDst(signDst string) *SigBasicVt { + return &SigBasicVt{dst: signDst} +} + +// Creates a new BLS key pair +func (b SigBasicVt) Keygen() (*PublicKeyVt, *SecretKey, error) { + return generateKeysVt() +} + +// Creates a new BLS key pair +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigBasicVt) KeygenWithSeed(ikm []byte) (*PublicKeyVt, *SecretKey, error) { + return generateKeysWithSeedVt(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigBasicVt) ThresholdKeygen(threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysVt(threshold, total) +} + +// ThresholdKeygenWithSeed generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures from input key material (ikm) +func (b SigBasicVt) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeedVt(ikm, threshold, total) +} + +// Computes a signature in G1 from sk, a secret key, and a message +func (b SigBasicVt) Sign(sk *SecretKey, msg []byte) (*SignatureVt, error) { + return sk.createSignatureVt(msg, b.dst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigBasicVt) PartialSign(sks *SecretKeyShare, msg []byte) (*PartialSignatureVt, error) { + return sks.partialSignVt(msg, b.dst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigBasicVt) CombineSignatures(sigs ...*PartialSignatureVt) (*SignatureVt, error) { + return combineSigsVt(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +func (b SigBasicVt) Verify(pk *PublicKeyVt, msg []byte, sig *SignatureVt) (bool, error) { + return pk.verifySignatureVt(msg, sig, b.dst) +} + +// The AggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// Each message must be different or this will return false. +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigBasicVt) AggregateVerify(pks []*PublicKeyVt, msgs [][]byte, sigs []*SignatureVt) (bool, error) { + if !allRowsUnique(msgs) { + return false, fmt.Errorf("all messages must be distinct") + } + asig, err := aggregateSignaturesVt(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, msgs, b.dst) +} + +// SigAugVt is minimal-signature-size scheme that doesn't support FastAggregateVerification. +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.2 +type SigAugVt struct { + dst string +} + +// Creates a new BLS message augmentation signature scheme with the standard domain separation tag used for signatures. +func NewSigAugVt() *SigAugVt { + return &SigAugVt{dst: blsSignatureAugVtDst} +} + +// Creates a new BLS message augmentation signature scheme with a custom domain separation tag used for signatures. +func NewSigAugVtWithDst(signDst string) *SigAugVt { + return &SigAugVt{dst: signDst} +} + +// Creates a new BLS key pair +func (b SigAugVt) Keygen() (*PublicKeyVt, *SecretKey, error) { + return generateKeysVt() +} + +// Creates a new BLS secret key +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigAugVt) KeygenWithSeed(ikm []byte) (*PublicKeyVt, *SecretKey, error) { + return generateKeysWithSeedVt(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigAugVt) ThresholdKeygen(threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysVt(threshold, total) +} + +// ThresholdKeygenWithSeed generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigAugVt) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeedVt(ikm, threshold, total) +} + +// Computes a signature in G1 from sk, a secret key, and a message +// See section 3.2.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02 +func (b SigAugVt) Sign(sk *SecretKey, msg []byte) (*SignatureVt, error) { + pk, err := sk.GetPublicKeyVt() + if err != nil { + return nil, err + } + bytes, err := pk.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("MarshalBinary failed") + } + bytes = append(bytes, msg...) + return sk.createSignatureVt(bytes, b.dst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigAugVt) PartialSign(sks *SecretKeyShare, pk *PublicKeyVt, msg []byte) (*PartialSignatureVt, error) { + if len(msg) == 0 { + return nil, fmt.Errorf("message cannot be empty or nil") + } + bytes, err := pk.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("MarshalBinary failed") + } + bytes = append(bytes, msg...) + return sks.partialSignVt(bytes, b.dst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigAugVt) CombineSignatures(sigs ...*PartialSignatureVt) (*SignatureVt, error) { + return combineSigsVt(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +// See section 3.2.2 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigAugVt) Verify(pk *PublicKeyVt, msg []byte, sig *SignatureVt) (bool, error) { + bytes, err := pk.MarshalBinary() + if err != nil { + return false, err + } + bytes = append(bytes, msg...) + return pk.verifySignatureVt(bytes, sig, b.dst) +} + +// The aggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// See section 3.2.3 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigAugVt) AggregateVerify(pks []*PublicKeyVt, msgs [][]byte, sigs []*SignatureVt) (bool, error) { + if len(pks) != len(msgs) { + return false, fmt.Errorf("the number of public keys does not match the number of messages: %v != %v", len(pks), len(msgs)) + } + data := make([][]byte, len(msgs)) + for i, msg := range msgs { + bytes, err := pks[i].MarshalBinary() + if err != nil { + return false, err + } + data[i] = append(bytes, msg...) + } + asig, err := aggregateSignaturesVt(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, data, b.dst) +} + +// SigEth2Vt supports signatures on Eth2. +// Internally is an alias for SigPopVt +type SigEth2Vt = SigPopVt + +// NewSigEth2Vt Creates a new BLS ETH2 signature scheme with the standard domain separation tag used for signatures. +func NewSigEth2Vt() *SigEth2Vt { + return NewSigPopVt() +} + +// SigPopVt is minimal-signature-size scheme that supports FastAggregateVerification +// and requires using proofs of possession to mitigate rogue-key attacks +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.3 +type SigPopVt struct { + sigDst string + popDst string +} + +// Creates a new BLS proof of possession signature scheme with the standard domain separation tag used for signatures. +func NewSigPopVt() *SigPopVt { + return &SigPopVt{sigDst: blsSignaturePopVtDst, popDst: blsPopProofVtDst} +} + +// Creates a new BLS message proof of possession signature scheme with a custom domain separation tag used for signatures. +func NewSigPopVtWithDst(signDst, popDst string) (*SigPopVt, error) { + if signDst == popDst { + return nil, fmt.Errorf("domain separation tags cannot be equal") + } + return &SigPopVt{sigDst: signDst, popDst: popDst}, nil +} + +// Creates a new BLS key pair +func (b SigPopVt) Keygen() (*PublicKeyVt, *SecretKey, error) { + return generateKeysVt() +} + +// Creates a new BLS secret key +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigPopVt) KeygenWithSeed(ikm []byte) (*PublicKeyVt, *SecretKey, error) { + return generateKeysWithSeedVt(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigPopVt) ThresholdKeygen(threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysVt(threshold, total) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigPopVt) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKeyVt, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeedVt(ikm, threshold, total) +} + +// Computes a signature in G1 from sk, a secret key, and a message +// See section 2.6 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) Sign(sk *SecretKey, msg []byte) (*SignatureVt, error) { + return sk.createSignatureVt(msg, b.sigDst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigPopVt) PartialSign(sks *SecretKeyShare, msg []byte) (*PartialSignatureVt, error) { + return sks.partialSignVt(msg, b.sigDst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigPopVt) CombineSignatures(sigs ...*PartialSignatureVt) (*SignatureVt, error) { + return combineSigsVt(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +// See section 2.7 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) Verify(pk *PublicKeyVt, msg []byte, sig *SignatureVt) (bool, error) { + return pk.verifySignatureVt(msg, sig, b.sigDst) +} + +// The aggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// Each message must be different or this will return false. +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02 +func (b SigPopVt) AggregateVerify(pks []*PublicKeyVt, msgs [][]byte, sigs []*SignatureVt) (bool, error) { + if !allRowsUnique(msgs) { + return false, fmt.Errorf("all messages must be distinct") + } + asig, err := aggregateSignaturesVt(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, msgs, b.sigDst) +} + +// Combine many signatures together to form a Multisignature. +// Multisignatures can be created when multiple signers jointly +// generate signatures over the same message. +func (b SigPopVt) AggregateSignatures(sigs ...*SignatureVt) (*MultiSignatureVt, error) { + g1, err := aggregateSignaturesVt(sigs...) + if err != nil { + return nil, err + } + return &MultiSignatureVt{value: g1.value}, nil +} + +// Combine many public keys together to form a Multipublickey. +// Multipublickeys are used to verify multisignatures. +func (b SigPopVt) AggregatePublicKeys(pks ...*PublicKeyVt) (*MultiPublicKeyVt, error) { + g2, err := aggregatePublicKeysVt(pks...) + if err != nil { + return nil, err + } + return &MultiPublicKeyVt{value: g2.value}, nil +} + +// Checks that a multisignature is valid for the message under the multi public key +// Similar to FastAggregateVerify except the keys and signatures have already been +// combined. See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-02 +func (b SigPopVt) VerifyMultiSignature(pk *MultiPublicKeyVt, msg []byte, sig *MultiSignatureVt) (bool, error) { + s := &SignatureVt{value: sig.value} + p := &PublicKeyVt{value: pk.value} + return p.verifySignatureVt(msg, s, b.sigDst) +} + +// FastAggregateVerify verifies an aggregated signature over the same message under the given public keys. +// See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) FastAggregateVerify(pks []*PublicKeyVt, msg []byte, asig *SignatureVt) (bool, error) { + apk, err := aggregatePublicKeysVt(pks...) + if err != nil { + return false, err + } + return apk.verifySignatureVt(msg, asig, b.sigDst) +} + +// FastAggregateVerifyConstituent verifies a list of signature over the same message under the given public keys. +// See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) FastAggregateVerifyConstituent(pks []*PublicKeyVt, msg []byte, sigs []*SignatureVt) (bool, error) { + asig, err := aggregateSignaturesVt(sigs...) + if err != nil { + return false, err + } + return b.FastAggregateVerify(pks, msg, asig) +} + +// Create a proof of possession for the corresponding public key. +// A proof of possession must be created for each public key to be used +// in FastAggregateVerify or a Multipublickey to avoid rogue key attacks. +// See section 3.3.2 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) PopProve(sk *SecretKey) (*ProofOfPossessionVt, error) { + return sk.createProofOfPossessionVt(b.popDst) +} + +// verify a proof of possession for the corresponding public key is valid. +// A proof of possession must be created for each public key to be used +// in FastAggregateVerify or a Multipublickey to avoid rogue key attacks. +// See section 3.3.3 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPopVt) PopVerify(pk *PublicKeyVt, pop1 *ProofOfPossessionVt) (bool, error) { + return pop1.verify(pk, b.popDst) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls_sig.go b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls_sig.go new file mode 100644 index 0000000000..793e9e3ca5 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/tiny_bls_sig.go @@ -0,0 +1,490 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package bls_sig + +import ( + "fmt" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" +) + +// Implement BLS signatures on the BLS12-381 curve +// according to https://crypto.standford.edu/~dabo/pubs/papers/BLSmultisig.html +// and https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +// this file implements signatures in G1 and public keys in G2. +// Public Keys and Signatures can be aggregated but the consumer +// must use proofs of possession to defend against rogue-key attacks. + +const ( + // Public key size in G2 + PublicKeyVtSize = 96 + // Signature size in G1 + SignatureVtSize = 48 + // Proof of Possession in G1 + ProofOfPossessionVtSize = 48 +) + +// Represents a public key in G2 +type PublicKeyVt struct { + value bls12381.G2 +} + +// Serialize a public key to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pk *PublicKeyVt) MarshalBinary() ([]byte, error) { + out := pk.value.ToCompressed() + return out[:], nil +} + +// Deserialize a public key from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the public key +// otherwise it will return an error +func (pk *PublicKeyVt) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeyVtSize { + return fmt.Errorf("public key must be %d bytes", PublicKeySize) + } + var blob [PublicKeyVtSize]byte + copy(blob[:], data) + p2, err := new(bls12381.G2).FromCompressed(&blob) + if err != nil { + return err + } + if p2.IsIdentity() == 1 { + return fmt.Errorf("public keys cannot be zero") + } + pk.value = *p2 + return nil +} + +// Represents a BLS signature in G1 +type SignatureVt struct { + value bls12381.G1 +} + +// Serialize a signature to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (sig *SignatureVt) MarshalBinary() ([]byte, error) { + out := sig.value.ToCompressed() + return out[:], nil +} + +func (sig *SignatureVt) verify(pk *PublicKeyVt, message []byte, signDstVt string) (bool, error) { + return pk.verifySignatureVt(message, sig, signDstVt) +} + +// The AggregateVerify algorithm checks an aggregated signature over +// several (PK, message) pairs. +// The Signature is the output of aggregateSignaturesVt +// Each message must be different or this will return false. +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (sig *SignatureVt) aggregateVerify(pks []*PublicKeyVt, msgs [][]byte, signDstVt string) (bool, error) { + return sig.coreAggregateVerify(pks, msgs, signDstVt) +} + +func (sig *SignatureVt) coreAggregateVerify(pks []*PublicKeyVt, msgs [][]byte, signDstVt string) (bool, error) { + if len(pks) < 1 { + return false, fmt.Errorf("at least one key is required") + } + if len(msgs) < 1 { + return false, fmt.Errorf("at least one message is required") + } + if len(pks) != len(msgs) { + return false, fmt.Errorf("the number of public keys does not match the number of messages: %v != %v", len(pks), len(msgs)) + } + if sig.value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("signature is not in the correct subgroup") + } + + engine := new(bls12381.Engine) + dst := []byte(signDstVt) + // e(H(m_1), pk_1)*...*e(H(m_N), pk_N) == e(s, g2) + // However, we use only one miller loop + // by doing the equivalent of + // e(H(m_1), pk_1)*...*e(H(m_N), pk_N) * e(s^-1, g2) == 1 + for i, pk := range pks { + if pk == nil { + return false, fmt.Errorf("public key at %d is nil", i) + } + if pk.value.IsIdentity() == 1 || pk.value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("public key at %d is not in the correct subgroup", i) + } + p1 := new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), msgs[i], dst) + engine.AddPair(p1, &pk.value) + } + engine.AddPairInvG2(&sig.value, new(bls12381.G2).Generator()) + return engine.Check(), nil +} + +// Deserialize a signature from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (sig *SignatureVt) UnmarshalBinary(data []byte) error { + if len(data) != SignatureVtSize { + return fmt.Errorf("signature must be %d bytes", SignatureSize) + } + var blob [SignatureVtSize]byte + copy(blob[:], data) + p1, err := new(bls12381.G1).FromCompressed(&blob) + if err != nil { + return err + } + if p1.IsIdentity() == 1 { + return fmt.Errorf("signatures cannot be zero") + } + sig.value = *p1 + return nil +} + +// Get the corresponding public key from a secret key +// Verifies the public key is in the correct subgroup +func (sk *SecretKey) GetPublicKeyVt() (*PublicKeyVt, error) { + result := new(bls12381.G2).Mul(new(bls12381.G2).Generator(), sk.value) + if result.InCorrectSubgroup() == 0 || result.IsIdentity() == 1 { + return nil, fmt.Errorf("point is not in correct subgroup") + } + return &PublicKeyVt{value: *result}, nil +} + +// Compute a signature from a secret key and message +// This signature is deterministic which protects against +// attacks arising from signing with bad randomness like +// the nonce reuse attack on ECDSA. `message` is +// hashed to a point in G1 as described in to +// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/?include_text=1 +// See Section 2.6 in https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +// nil message is not permitted but empty slice is allowed +func (sk *SecretKey) createSignatureVt(message []byte, dstVt string) (*SignatureVt, error) { + if message == nil { + return nil, fmt.Errorf("message cannot be nil") + } + if sk.value.IsZero() == 1 { + return nil, fmt.Errorf("invalid secret key") + } + p1 := new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), message, []byte(dstVt)) + result := new(bls12381.G1).Mul(p1, sk.value) + if result.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("point is not in correct subgroup") + } + return &SignatureVt{value: *result}, nil +} + +// Verify a signature is valid for the message under this public key. +// See Section 2.7 in https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (pk PublicKeyVt) verifySignatureVt(message []byte, signature *SignatureVt, dstVt string) (bool, error) { + if signature == nil || message == nil || pk.value.IsIdentity() == 1 { + return false, fmt.Errorf("signature and message and public key cannot be nil or zero") + } + if signature.value.IsIdentity() == 1 || signature.value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("signature is not in the correct subgroup") + } + engine := new(bls12381.Engine) + + p1 := new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), message, []byte(dstVt)) + // e(H(m), pk) == e(s, g2) + // However, we can reduce the number of miller loops + // by doing the equivalent of + // e(H(m)^-1, pk) * e(s, g2) == 1 + engine.AddPairInvG1(p1, &pk.value) + engine.AddPair(&signature.value, new(bls12381.G2).Generator()) + return engine.Check(), nil +} + +// Combine public keys into one aggregated key +func aggregatePublicKeysVt(pks ...*PublicKeyVt) (*PublicKeyVt, error) { + if len(pks) < 1 { + return nil, fmt.Errorf("at least one public key is required") + } + result := new(bls12381.G2).Identity() + for i, k := range pks { + if k == nil { + return nil, fmt.Errorf("key at %d is nil, keys cannot be nil", i) + } + if k.value.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("key at %d is not in the correct subgroup", i) + } + result.Add(result, &k.value) + } + return &PublicKeyVt{value: *result}, nil +} + +// Combine signatures into one aggregated signature +func aggregateSignaturesVt(sigs ...*SignatureVt) (*SignatureVt, error) { + if len(sigs) < 1 { + return nil, fmt.Errorf("at least one signature is required") + } + result := new(bls12381.G1).Identity() + for i, s := range sigs { + if s == nil { + return nil, fmt.Errorf("signature at %d is nil, signature cannot be nil", i) + } + if s.value.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("signature at %d is not in the correct subgroup", i) + } + result.Add(result, &s.value) + } + return &SignatureVt{value: *result}, nil +} + +// A proof of possession scheme uses a separate public key validation +// step, called a proof of possession, to defend against rogue key +// attacks. This enables an optimization to aggregate signature +// verification for the case that all signatures are on the same +// message. +type ProofOfPossessionVt struct { + value bls12381.G1 +} + +// Generates a proof-of-possession (PoP) for this secret key. The PoP signature should be verified before +// before accepting any aggregate signatures related to the corresponding pubkey. +func (sk *SecretKey) createProofOfPossessionVt(popDstVt string) (*ProofOfPossessionVt, error) { + pk, err := sk.GetPublicKeyVt() + if err != nil { + return nil, err + } + msg, err := pk.MarshalBinary() + if err != nil { + return nil, err + } + sig, err := sk.createSignatureVt(msg, popDstVt) + if err != nil { + return nil, err + } + return &ProofOfPossessionVt{value: sig.value}, nil +} + +// Serialize a proof of possession to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pop *ProofOfPossessionVt) MarshalBinary() ([]byte, error) { + out := pop.value.ToCompressed() + return out[:], nil +} + +// Deserialize a proof of possession from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (pop *ProofOfPossessionVt) UnmarshalBinary(data []byte) error { + p1 := new(SignatureVt) + err := p1.UnmarshalBinary(data) + if err != nil { + return err + } + pop.value = p1.value + return nil +} + +// Verifies that PoP is valid for this pubkey. In order to prevent rogue key attacks, a PoP must be validated +// for each pubkey in an aggregated signature. +func (pop *ProofOfPossessionVt) verify(pk *PublicKeyVt, popDstVt string) (bool, error) { + if pk == nil { + return false, fmt.Errorf("public key cannot be nil") + } + msg, err := pk.MarshalBinary() + if err != nil { + return false, err + } + return pk.verifySignatureVt(msg, &SignatureVt{value: pop.value}, popDstVt) +} + +// Represents an MultiSignature in G1. A multisignature is used when multiple signatures +// are calculated over the same message vs an aggregate signature where each message signed +// is a unique. +type MultiSignatureVt struct { + value bls12381.G1 +} + +// Serialize a multi-signature to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (sig *MultiSignatureVt) MarshalBinary() ([]byte, error) { + out := sig.value.ToCompressed() + return out[:], nil +} + +// Check a multisignature is valid for a multipublickey and a message +func (sig *MultiSignatureVt) verify(pk *MultiPublicKeyVt, message []byte, signDstVt string) (bool, error) { + if pk == nil { + return false, fmt.Errorf("public key cannot be nil") + } + p := &PublicKeyVt{value: pk.value} + return p.verifySignatureVt(message, &SignatureVt{value: sig.value}, signDstVt) +} + +// Deserialize a signature from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (sig *MultiSignatureVt) UnmarshalBinary(data []byte) error { + if len(data) != SignatureVtSize { + return fmt.Errorf("multi signature must be %v bytes", SignatureSize) + } + s1 := new(SignatureVt) + err := s1.UnmarshalBinary(data) + if err != nil { + return err + } + sig.value = s1.value + return nil +} + +// Represents accumulated multiple Public Keys in G2 for verifying a multisignature +type MultiPublicKeyVt struct { + value bls12381.G2 +} + +// Serialize a public key to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pk *MultiPublicKeyVt) MarshalBinary() ([]byte, error) { + out := pk.value.ToCompressed() + return out[:], nil +} + +// Deserialize a public key from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the public key +// otherwise it will return an error +func (pk *MultiPublicKeyVt) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeyVtSize { + return fmt.Errorf("multi public key must be %v bytes", PublicKeySize) + } + p2 := new(PublicKeyVt) + err := p2.UnmarshalBinary(data) + if err != nil { + return err + } + pk.value = p2.value + return nil +} + +// Check a multisignature is valid for a multipublickey and a message +func (pk *MultiPublicKeyVt) verify(message []byte, sig *MultiSignatureVt, signDstVt string) (bool, error) { + return sig.verify(pk, message, signDstVt) +} + +// PartialSignatureVt represents threshold Gap Diffie-Hellman BLS signature +// that can be combined with other partials to yield a completed BLS signature +// See section 3.2 in +type PartialSignatureVt struct { + identifier byte + signature bls12381.G1 +} + +// partialSignVt creates a partial signature that can be combined with other partial signatures +// to yield a complete signature +func (sks *SecretKeyShare) partialSignVt(message []byte, signDst string) (*PartialSignatureVt, error) { + if len(message) == 0 { + return nil, fmt.Errorf("message cannot be empty or nil") + } + p1 := new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), message, []byte(signDst)) + + var blob [SecretKeySize]byte + copy(blob[:], internal.ReverseScalarBytes(sks.value)) + s, err := bls12381.Bls12381FqNew().SetBytes(&blob) + if err != nil { + return nil, err + } + result := new(bls12381.G1).Mul(p1, s) + if result.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("point is not on correct subgroup") + } + return &PartialSignatureVt{identifier: sks.identifier, signature: *result}, nil +} + +// combineSigsVt gathers partial signatures and yields a complete signature +func combineSigsVt(partials []*PartialSignatureVt) (*SignatureVt, error) { + if len(partials) < 2 { + return nil, fmt.Errorf("must have at least 2 partial signatures") + } + if len(partials) > 255 { + return nil, fmt.Errorf("unsupported to combine more than 255 signatures") + } + + xVars, yVars, err := splitXYVt(partials) + + if err != nil { + return nil, err + } + + sTmp := new(bls12381.G1).Identity() + sig := new(bls12381.G1).Identity() + + // Lagrange interpolation + basis := bls12381.Bls12381FqNew() + for i, xi := range xVars { + basis.SetOne() + + for j, xj := range xVars { + if i == j { + continue + } + + num := bls12381.Bls12381FqNew().Neg(xj) // x - x_m + den := bls12381.Bls12381FqNew().Sub(xi, xj) // x_j - x_m + _, wasInverted := den.Invert(den) + // wasInverted == false if den == 0 + if !wasInverted { + return nil, fmt.Errorf("signatures cannot be recombined") + } + basis.Mul(basis, num.Mul(num, den)) + } + sTmp.Mul(yVars[i], basis) + sig.Add(sig, sTmp) + } + if sig.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("signature is not in the correct subgroup") + } + + return &SignatureVt{value: *sig}, nil +} + +// Ensure no duplicates x values and convert x values to field elements +func splitXYVt(partials []*PartialSignatureVt) ([]*native.Field, []*bls12381.G1, error) { + x := make([]*native.Field, len(partials)) + y := make([]*bls12381.G1, len(partials)) + + dup := make(map[byte]bool) + + for i, sp := range partials { + if sp == nil { + return nil, nil, fmt.Errorf("partial signature cannot be nil") + } + if _, exists := dup[sp.identifier]; exists { + return nil, nil, fmt.Errorf("duplicate signature included") + } + if sp.signature.InCorrectSubgroup() == 0 { + return nil, nil, fmt.Errorf("signature is not in the correct subgroup") + } + dup[sp.identifier] = true + x[i] = bls12381.Bls12381FqNew().SetUint64(uint64(sp.identifier)) + y[i] = &sp.signature + } + return x, y, nil +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls.go b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls.go new file mode 100644 index 0000000000..a827b18833 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls.go @@ -0,0 +1,446 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package bls_sig + +import ( + "fmt" +) + +const ( + // Domain separation tag for basic signatures + // according to section 4.2.1 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignatureBasicDst = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_" + // Domain separation tag for basic signatures + // according to section 4.2.2 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignatureAugDst = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_" + // Domain separation tag for proof of possession signatures + // according to section 4.2.3 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsSignaturePopDst = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_" + // Domain separation tag for proof of possession proofs + // according to section 4.2.3 in + // https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 + blsPopProofDst = "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_" +) + +type BlsScheme interface { + Keygen() (*PublicKey, *SecretKey, error) + KeygenWithSeed(ikm []byte) (*PublicKey, *SecretKey, error) + Sign(sk *SecretKey, msg []byte) (*Signature, error) + Verify(pk *PublicKey, msg []byte, sig *Signature) bool + AggregateVerify(pks []*PublicKey, msgs [][]byte, sigs []*Signature) bool +} + +// generateKeys creates 32 bytes of random data to be fed to +// generateKeysWithSeed +func generateKeys() (*PublicKey, *SecretKey, error) { + ikm, err := generateRandBytes(32) + if err != nil { + return nil, nil, err + } + return generateKeysWithSeed(ikm) +} + +// generateKeysWithSeed generates a BLS key pair given input key material (ikm) +func generateKeysWithSeed(ikm []byte) (*PublicKey, *SecretKey, error) { + sk, err := new(SecretKey).Generate(ikm) + if err != nil { + return nil, nil, err + } + pk, err := sk.GetPublicKey() + if err != nil { + return nil, nil, err + } + return pk, sk, nil +} + +// thresholdGenerateKeys will generate random secret key shares and the corresponding public key +func thresholdGenerateKeys(threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + pk, sk, err := generateKeys() + if err != nil { + return nil, nil, err + } + shares, err := thresholdizeSecretKey(sk, threshold, total) + if err != nil { + return nil, nil, err + } + return pk, shares, nil +} + +// thresholdGenerateKeysWithSeed will generate random secret key shares and the corresponding public key +// using the corresponding seed `ikm` +func thresholdGenerateKeysWithSeed(ikm []byte, threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + pk, sk, err := generateKeysWithSeed(ikm) + if err != nil { + return nil, nil, err + } + shares, err := thresholdizeSecretKey(sk, threshold, total) + if err != nil { + return nil, nil, err + } + return pk, shares, nil +} + +// SigBasic is minimal-pubkey-size scheme that doesn't support FastAggregateVerificiation. +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.1 +type SigBasic struct { + dst string +} + +// Creates a new BLS basic signature scheme with the standard domain separation tag used for signatures. +func NewSigBasic() *SigBasic { + return &SigBasic{dst: blsSignatureBasicDst} +} + +// Creates a new BLS basic signature scheme with a custom domain separation tag used for signatures. +func NewSigBasicWithDst(signDst string) *SigBasic { + return &SigBasic{dst: signDst} +} + +// Creates a new BLS key pair +func (b SigBasic) Keygen() (*PublicKey, *SecretKey, error) { + return generateKeys() +} + +// Creates a new BLS key pair +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigBasic) KeygenWithSeed(ikm []byte) (*PublicKey, *SecretKey, error) { + return generateKeysWithSeed(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigBasic) ThresholdKeygen(threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeys(threshold, total) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigBasic) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeed(ikm, threshold, total) +} + +// Computes a signature in G2 from sk, a secret key, and a message +func (b SigBasic) Sign(sk *SecretKey, msg []byte) (*Signature, error) { + return sk.createSignature(msg, b.dst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigBasic) PartialSign(sks *SecretKeyShare, msg []byte) (*PartialSignature, error) { + return sks.partialSign(msg, b.dst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigBasic) CombineSignatures(sigs ...*PartialSignature) (*Signature, error) { + return combineSigs(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +func (b SigBasic) Verify(pk *PublicKey, msg []byte, sig *Signature) (bool, error) { + return pk.verifySignature(msg, sig, b.dst) +} + +// The AggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// Each message must be different or this will return false. +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigBasic) AggregateVerify(pks []*PublicKey, msgs [][]byte, sigs []*Signature) (bool, error) { + if !allRowsUnique(msgs) { + return false, fmt.Errorf("all messages must be distinct") + } + asig, err := aggregateSignatures(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, msgs, b.dst) +} + +// SigAug is minimal-pubkey-size scheme that doesn't support FastAggregateVerificiation. +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.2 +type SigAug struct { + dst string +} + +// Creates a new BLS message augmentation signature scheme with the standard domain separation tag used for signatures. +func NewSigAug() *SigAug { + return &SigAug{dst: blsSignatureAugDst} +} + +// Creates a new BLS message augmentation signature scheme with a custom domain separation tag used for signatures. +func NewSigAugWithDst(signDst string) *SigAug { + return &SigAug{dst: signDst} +} + +// Creates a new BLS key pair +func (b SigAug) Keygen() (*PublicKey, *SecretKey, error) { + return generateKeys() +} + +// Creates a new BLS secret key +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigAug) KeygenWithSeed(ikm []byte) (*PublicKey, *SecretKey, error) { + return generateKeysWithSeed(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigAug) ThresholdKeygen(threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeys(threshold, total) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigAug) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeed(ikm, threshold, total) +} + +// Computes a signature in G1 from sk, a secret key, and a message +// See section 3.2.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigAug) Sign(sk *SecretKey, msg []byte) (*Signature, error) { + if len(msg) == 0 { + return nil, fmt.Errorf("message cannot be empty or nil") + } + + pk, err := sk.GetPublicKey() + if err != nil { + return nil, err + } + bytes, err := pk.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("MarshalBinary failed") + } + bytes = append(bytes, msg...) + return sk.createSignature(bytes, b.dst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigAug) PartialSign(sks *SecretKeyShare, pk *PublicKey, msg []byte) (*PartialSignature, error) { + if len(msg) == 0 { + return nil, fmt.Errorf("message cannot be empty or nil") + } + + bytes, err := pk.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("MarshalBinary failed") + } + bytes = append(bytes, msg...) + return sks.partialSign(bytes, b.dst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigAug) CombineSignatures(sigs ...*PartialSignature) (*Signature, error) { + return combineSigs(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +// See section 3.2.2 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigAug) Verify(pk *PublicKey, msg []byte, sig *Signature) (bool, error) { + bytes, err := pk.MarshalBinary() + if err != nil { + return false, err + } + bytes = append(bytes, msg...) + return pk.verifySignature(bytes, sig, b.dst) +} + +// The AggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// See section 3.2.3 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigAug) AggregateVerify(pks []*PublicKey, msgs [][]byte, sigs []*Signature) (bool, error) { + if len(pks) != len(msgs) { + return false, fmt.Errorf("the number of public keys does not match the number of messages: %v != %v", len(pks), len(msgs)) + } + data := make([][]byte, len(msgs)) + for i, msg := range msgs { + bytes, err := pks[i].MarshalBinary() + if err != nil { + return false, err + } + data[i] = append(bytes, msg...) + } + asig, err := aggregateSignatures(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, data, b.dst) +} + +// SigEth2 supports signatures on Eth2. +// Internally is an alias for SigPop +type SigEth2 = SigPop + +// NewSigEth2 Creates a new BLS ETH2 signature scheme with the standard domain separation tag used for signatures. +func NewSigEth2() *SigEth2 { + return NewSigPop() +} + +// SigPop is minimal-pubkey-size scheme that supports FastAggregateVerification +// and requires using proofs of possession to mitigate rogue-key attacks +// see: https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03#section-4.2.3 +type SigPop struct { + sigDst string + popDst string +} + +// Creates a new BLS proof of possession signature scheme with the standard domain separation tag used for signatures. +func NewSigPop() *SigPop { + return &SigPop{sigDst: blsSignaturePopDst, popDst: blsPopProofDst} +} + +// Creates a new BLS message proof of possession signature scheme with a custom domain separation tag used for signatures. +func NewSigPopWithDst(signDst, popDst string) (*SigPop, error) { + if signDst == popDst { + return nil, fmt.Errorf("domain separation tags cannot be equal") + } + return &SigPop{sigDst: signDst, popDst: popDst}, nil +} + +// Creates a new BLS key pair +func (b SigPop) Keygen() (*PublicKey, *SecretKey, error) { + return generateKeys() +} + +// Creates a new BLS secret key +// Input key material (ikm) MUST be at least 32 bytes long, +// but it MAY be longer. +func (b SigPop) KeygenWithSeed(ikm []byte) (*PublicKey, *SecretKey, error) { + return generateKeysWithSeed(ikm) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigPop) ThresholdKeygen(threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeys(threshold, total) +} + +// ThresholdKeyGen generates a public key and `total` secret key shares such that +// `threshold` of them can be combined in signatures +func (b SigPop) ThresholdKeygenWithSeed(ikm []byte, threshold, total uint) (*PublicKey, []*SecretKeyShare, error) { + return thresholdGenerateKeysWithSeed(ikm, threshold, total) +} + +// Computes a signature in G2 from sk, a secret key, and a message +// See section 2.6 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) Sign(sk *SecretKey, msg []byte) (*Signature, error) { + return sk.createSignature(msg, b.sigDst) +} + +// Compute a partial signature in G2 that can be combined with other partial signature +func (b SigPop) PartialSign(sks *SecretKeyShare, msg []byte) (*PartialSignature, error) { + return sks.partialSign(msg, b.sigDst) +} + +// CombineSignatures takes partial signatures to yield a completed signature +func (b SigPop) CombineSignatures(sigs ...*PartialSignature) (*Signature, error) { + return combineSigs(sigs) +} + +// Checks that a signature is valid for the message under the public key pk +// See section 2.7 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) Verify(pk *PublicKey, msg []byte, sig *Signature) (bool, error) { + return pk.verifySignature(msg, sig, b.sigDst) +} + +// The aggregateVerify algorithm checks an aggregated signature over +// several (PK, message, signature) pairs. +// Each message must be different or this will return false. +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) AggregateVerify(pks []*PublicKey, msgs [][]byte, sigs []*Signature) (bool, error) { + if !allRowsUnique(msgs) { + return false, fmt.Errorf("all messages must be distinct") + } + asig, err := aggregateSignatures(sigs...) + if err != nil { + return false, err + } + return asig.aggregateVerify(pks, msgs, b.sigDst) +} + +// Combine many signatures together to form a Multisignature. +// Multisignatures can be created when multiple signers jointly +// generate signatures over the same message. +func (b SigPop) AggregateSignatures(sigs ...*Signature) (*MultiSignature, error) { + g1, err := aggregateSignatures(sigs...) + if err != nil { + return nil, err + } + return &MultiSignature{value: g1.Value}, nil +} + +// Combine many public keys together to form a Multipublickey. +// Multipublickeys are used to verify multisignatures. +func (b SigPop) AggregatePublicKeys(pks ...*PublicKey) (*MultiPublicKey, error) { + g2, err := aggregatePublicKeys(pks...) + if err != nil { + return nil, err + } + return &MultiPublicKey{value: g2.value}, nil +} + +// Checks that a multisignature is valid for the message under the multi public key +// Similar to FastAggregateVerify except the keys and signatures have already been +// combined. See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) VerifyMultiSignature(pk *MultiPublicKey, msg []byte, sig *MultiSignature) (bool, error) { + s := &Signature{Value: sig.value} + p := &PublicKey{value: pk.value} + return p.verifySignature(msg, s, b.sigDst) +} + +// FastAggregateVerify verifies an aggregated signature against the specified message and set of public keys. +// See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) FastAggregateVerify(pks []*PublicKey, msg []byte, asig *Signature) (bool, error) { + apk, err := aggregatePublicKeys(pks...) + if err != nil { + return false, err + } + return apk.verifySignature(msg, asig, b.sigDst) +} + +// FastAggregateVerifyConstituent aggregates all constituent signatures and the verifies +// them against the specified message and public keys +// See section 3.3.4 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) FastAggregateVerifyConstituent(pks []*PublicKey, msg []byte, sigs []*Signature) (bool, error) { + // Aggregate the constituent signatures + asig, err := aggregateSignatures(sigs...) + if err != nil { + return false, err + } + // And verify + return b.FastAggregateVerify(pks, msg, asig) +} + +// Create a proof of possession for the corresponding public key. +// A proof of possession must be created for each public key to be used +// in FastAggregateVerify or a Multipublickey to avoid rogue key attacks. +// See section 3.3.2 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) PopProve(sk *SecretKey) (*ProofOfPossession, error) { + return sk.createProofOfPossession(b.popDst) +} + +// verify a proof of possession for the corresponding public key is valid. +// A proof of possession must be created for each public key to be used +// in FastAggregateVerify or a Multipublickey to avoid rogue key attacks. +// See section 3.3.3 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (b SigPop) PopVerify(pk *PublicKey, pop2 *ProofOfPossession) (bool, error) { + return pop2.verify(pk, b.popDst) +} diff --git a/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls_sig.go b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls_sig.go new file mode 100644 index 0000000000..c394bacc21 --- /dev/null +++ b/vendor/github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig/usual_bls_sig.go @@ -0,0 +1,492 @@ +// +// Copyright Coinbase, Inc. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package bls_sig + +import ( + "fmt" + + "github.com/coinbase/kryptology/internal" + "github.com/coinbase/kryptology/pkg/core/curves/native" + "github.com/coinbase/kryptology/pkg/core/curves/native/bls12381" +) + +// Implement BLS signatures on the BLS12-381 curve +// according to https://crypto.standford.edu/~dabo/pubs/papers/BLSmultisig.html +// and https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +// this file implements signatures in G2 and public keys in G1. +// Public Keys and Signatures can be aggregated but the consumer +// must use proofs of possession to defend against rogue-key attacks. + +const ( + // Public key size in G1 + PublicKeySize = 48 + // Signature size in G2 + SignatureSize = 96 + // Proof of Possession in G2 + ProofOfPossessionSize = 96 +) + +// Represents a public key in G1 +type PublicKey struct { + value bls12381.G1 +} + +// Serialize a public key to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pk PublicKey) MarshalBinary() ([]byte, error) { + out := pk.value.ToCompressed() + return out[:], nil +} + +// Deserialize a public key from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the public key +// otherwise it will return an error +func (pk *PublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return fmt.Errorf("public key must be %d bytes", PublicKeySize) + } + var blob [PublicKeySize]byte + copy(blob[:], data) + p1, err := new(bls12381.G1).FromCompressed(&blob) + if err != nil { + return err + } + if p1.IsIdentity() == 1 { + return fmt.Errorf("public keys cannot be zero") + } + pk.value = *p1 + return nil +} + +// Represents a BLS signature in G2 +type Signature struct { + Value bls12381.G2 +} + +// Serialize a signature to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (sig Signature) MarshalBinary() ([]byte, error) { + out := sig.Value.ToCompressed() + return out[:], nil +} + +func (sig Signature) verify(pk *PublicKey, message []byte, signDst string) (bool, error) { + return pk.verifySignature(message, &sig, signDst) +} + +// The AggregateVerify algorithm checks an aggregated signature over +// several (PK, message) pairs. +// The Signature is the output of aggregateSignatures +// Each message must be different or this will return false +// See section 3.1.1 from +// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (sig Signature) aggregateVerify(pks []*PublicKey, msgs [][]byte, signDst string) (bool, error) { + return sig.coreAggregateVerify(pks, msgs, signDst) +} + +func (sig Signature) coreAggregateVerify(pks []*PublicKey, msgs [][]byte, signDst string) (bool, error) { + if len(pks) < 1 { + return false, fmt.Errorf("at least one key is required") + } + if len(msgs) < 1 { + return false, fmt.Errorf("at least one message is required") + } + if len(pks) != len(msgs) { + return false, fmt.Errorf("the number of public keys does not match the number of messages: %v != %v", len(pks), len(msgs)) + } + if sig.Value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("signature is not in the correct subgroup") + } + + dst := []byte(signDst) + engine := new(bls12381.Engine) + // e(pk_1, H(m_1))*...*e(pk_N, H(m_N)) == e(g1, s) + // However, we use only one miller loop + // by doing the equivalent of + // e(pk_1, H(m_1))*...*e(pk_N, H(m_N)) * e(g1^-1, s) == 1 + for i, pk := range pks { + if pk == nil { + return false, fmt.Errorf("public key at %d is nil", i) + } + if pk.value.IsIdentity() == 1 || pk.value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("public key at %d is not in the correct subgroup", i) + } + p2 := new(bls12381.G2).Hash(native.EllipticPointHasherSha256(), msgs[i], dst) + engine.AddPair(&pk.value, p2) + } + engine.AddPairInvG1(new(bls12381.G1).Generator(), &sig.Value) + return engine.Check(), nil +} + +// Deserialize a signature from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (sig *Signature) UnmarshalBinary(data []byte) error { + if len(data) != SignatureSize { + return fmt.Errorf("signature must be %d bytes", SignatureSize) + } + var blob [SignatureSize]byte + copy(blob[:], data) + p2, err := new(bls12381.G2).FromCompressed(&blob) + if err != nil { + return err + } + if p2.IsIdentity() == 1 { + return fmt.Errorf("signatures cannot be zero") + } + sig.Value = *p2 + return nil +} + +// Get the corresponding public key from a secret key +// Verifies the public key is in the correct subgroup +func (sk SecretKey) GetPublicKey() (*PublicKey, error) { + result := new(bls12381.G1).Generator() + result.Mul(result, sk.value) + if result.InCorrectSubgroup() == 0 || result.IsIdentity() == 1 { + return nil, fmt.Errorf("point is not in correct subgroup") + } + return &PublicKey{value: *result}, nil +} + +// Compute a signature from a secret key and message +// This signature is deterministic which protects against +// attacks arising from signing with bad randomness like +// the nonce reuse attack on ECDSA. `message` is +// hashed to a point in G2 as described in to +// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/?include_text=1 +// See Section 2.6 in https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +// nil message is not permitted but empty slice is allowed +func (sk SecretKey) createSignature(message []byte, dst string) (*Signature, error) { + if message == nil { + return nil, fmt.Errorf("message cannot be nil") + } + if sk.value.IsZero() == 1 { + return nil, fmt.Errorf("invalid secret key") + } + p2 := new(bls12381.G2).Hash(native.EllipticPointHasherSha256(), message, []byte(dst)) + result := new(bls12381.G2).Mul(p2, sk.value) + if result.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("point is not on correct subgroup") + } + return &Signature{Value: *result}, nil +} + +// Verify a signature is valid for the message under this public key. +// See Section 2.7 in https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03 +func (pk PublicKey) verifySignature(message []byte, signature *Signature, dst string) (bool, error) { + if signature == nil || message == nil || pk.value.IsIdentity() == 1 { + return false, fmt.Errorf("signature and message and public key cannot be nil or zero") + } + if signature.Value.IsIdentity() == 1 || signature.Value.InCorrectSubgroup() == 0 { + return false, fmt.Errorf("signature is not in the correct subgroup") + } + engine := new(bls12381.Engine) + + p2 := new(bls12381.G2).Hash(native.EllipticPointHasherSha256(), message, []byte(dst)) + // e(pk, H(m)) == e(g1, s) + // However, we can reduce the number of miller loops + // by doing the equivalent of + // e(pk^-1, H(m)) * e(g1, s) == 1 + engine.AddPair(&pk.value, p2) + engine.AddPairInvG1(new(bls12381.G1).Generator(), &signature.Value) + return engine.Check(), nil +} + +// Combine public keys into one aggregated key +func aggregatePublicKeys(pks ...*PublicKey) (*PublicKey, error) { + if len(pks) < 1 { + return nil, fmt.Errorf("at least one public key is required") + } + result := new(bls12381.G1).Identity() + for i, k := range pks { + if k == nil { + return nil, fmt.Errorf("key at %d is nil, keys cannot be nil", i) + } + if k.value.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("key at %d is not in the correct subgroup", i) + } + result.Add(result, &k.value) + } + return &PublicKey{value: *result}, nil +} + +// Combine signatures into one aggregated signature +func aggregateSignatures(sigs ...*Signature) (*Signature, error) { + if len(sigs) < 1 { + return nil, fmt.Errorf("at least one signature is required") + } + result := new(bls12381.G2).Identity() + for i, s := range sigs { + if s == nil { + return nil, fmt.Errorf("signature at %d is nil, signature cannot be nil", i) + } + if s.Value.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("signature at %d is not in the correct subgroup", i) + } + result.Add(result, &s.Value) + } + return &Signature{Value: *result}, nil +} + +// A proof of possession scheme uses a separate public key validation +// step, called a proof of possession, to defend against rogue key +// attacks. This enables an optimization to aggregate signature +// verification for the case that all signatures are on the same +// message. +type ProofOfPossession struct { + value bls12381.G2 +} + +// Generates a proof-of-possession (PoP) for this secret key. The PoP signature should be verified before +// before accepting any aggregate signatures related to the corresponding pubkey. +func (sk SecretKey) createProofOfPossession(popDst string) (*ProofOfPossession, error) { + pk, err := sk.GetPublicKey() + if err != nil { + return nil, err + } + msg, err := pk.MarshalBinary() + if err != nil { + return nil, err + } + sig, err := sk.createSignature(msg, popDst) + if err != nil { + return nil, err + } + return &ProofOfPossession{value: sig.Value}, nil +} + +// Serialize a proof of possession to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pop ProofOfPossession) MarshalBinary() ([]byte, error) { + out := pop.value.ToCompressed() + return out[:], nil +} + +// Deserialize a proof of possession from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (pop *ProofOfPossession) UnmarshalBinary(data []byte) error { + p2 := new(Signature) + err := p2.UnmarshalBinary(data) + if err != nil { + return err + } + pop.value = p2.Value + return nil +} + +// Verifies that PoP is valid for this pubkey. In order to prevent rogue key attacks, a PoP must be validated +// for each pubkey in an aggregated signature. +func (pop ProofOfPossession) verify(pk *PublicKey, popDst string) (bool, error) { + if pk == nil { + return false, fmt.Errorf("public key cannot be nil") + } + msg, err := pk.MarshalBinary() + if err != nil { + return false, err + } + return pk.verifySignature(msg, &Signature{Value: pop.value}, popDst) +} + +// Represents an MultiSignature in G2. A multisignature is used when multiple signatures +// are calculated over the same message vs an aggregate signature where each message signed +// is a unique. +type MultiSignature struct { + value bls12381.G2 +} + +// Serialize a multi-signature to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (sig MultiSignature) MarshalBinary() ([]byte, error) { + out := sig.value.ToCompressed() + return out[:], nil +} + +// Check a multisignature is valid for a multipublickey and a message +func (sig MultiSignature) verify(pk *MultiPublicKey, message []byte, signDst string) (bool, error) { + if pk == nil { + return false, fmt.Errorf("public key cannot be nil") + } + p := PublicKey{value: pk.value} + return p.verifySignature(message, &Signature{Value: sig.value}, signDst) +} + +// Deserialize a signature from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the Signature +// otherwise it will return an error +func (sig *MultiSignature) UnmarshalBinary(data []byte) error { + if len(data) != SignatureSize { + return fmt.Errorf("multi signature must be %v bytes", SignatureSize) + } + s2 := new(Signature) + err := s2.UnmarshalBinary(data) + if err != nil { + return err + } + sig.value = s2.Value + return nil +} + +// Represents accumulated multiple Public Keys in G1 for verifying a multisignature +type MultiPublicKey struct { + value bls12381.G1 +} + +// Serialize a public key to a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (pk MultiPublicKey) MarshalBinary() ([]byte, error) { + out := pk.value.ToCompressed() + return out[:], nil +} + +// Deserialize a public key from a byte array in compressed form. +// See +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +// If successful, it will assign the public key +// otherwise it will return an error +func (pk *MultiPublicKey) UnmarshalBinary(data []byte) error { + if len(data) != PublicKeySize { + return fmt.Errorf("multi public key must be %v bytes", PublicKeySize) + } + p1 := new(PublicKey) + err := p1.UnmarshalBinary(data) + if err != nil { + return err + } + pk.value = p1.value + return nil +} + +// Check a multisignature is valid for a multipublickey and a message +func (pk MultiPublicKey) verify(message []byte, sig *MultiSignature, signDst string) (bool, error) { + return sig.verify(&pk, message, signDst) +} + +// PartialSignature represents threshold Gap Diffie-Hellman BLS signature +// that can be combined with other partials to yield a completed BLS signature +// See section 3.2 in +type PartialSignature struct { + Identifier byte + Signature bls12381.G2 +} + +// partialSign creates a partial signature that can be combined with other partial signatures +// to yield a complete signature +func (sks SecretKeyShare) partialSign(message []byte, signDst string) (*PartialSignature, error) { + if len(message) == 0 { + return nil, fmt.Errorf("message cannot be empty or nil") + } + p2 := new(bls12381.G2).Hash(native.EllipticPointHasherSha256(), message, []byte(signDst)) + + var blob [SecretKeySize]byte + copy(blob[:], internal.ReverseScalarBytes(sks.value)) + s, err := bls12381.Bls12381FqNew().SetBytes(&blob) + if err != nil { + return nil, err + } + result := new(bls12381.G2).Mul(p2, s) + if result.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("point is not on correct subgroup") + } + return &PartialSignature{Identifier: sks.identifier, Signature: *result}, nil +} + +// combineSigs gathers partial signatures and yields a complete signature +func combineSigs(partials []*PartialSignature) (*Signature, error) { + if len(partials) < 2 { + return nil, fmt.Errorf("must have at least 2 partial signatures") + } + if len(partials) > 255 { + return nil, fmt.Errorf("unsupported to combine more than 255 signatures") + } + + // Don't know the actual values so put the minimum + xVars, yVars, err := splitXY(partials) + + if err != nil { + return nil, err + } + + sTmp := new(bls12381.G2).Identity() + sig := new(bls12381.G2).Identity() + + // Lagrange interpolation + basis := bls12381.Bls12381FqNew().SetOne() + for i, xi := range xVars { + basis.SetOne() + + for j, xj := range xVars { + if i == j { + continue + } + + num := bls12381.Bls12381FqNew().Neg(xj) // - x_m + den := bls12381.Bls12381FqNew().Sub(xi, xj) // x_j - x_m + _, wasInverted := den.Invert(den) + // wasInverted == false if den == 0 + if !wasInverted { + return nil, fmt.Errorf("signatures cannot be recombined") + } + basis.Mul(basis, num.Mul(num, den)) + } + sTmp.Mul(yVars[i], basis) + sig.Add(sig, sTmp) + } + if sig.InCorrectSubgroup() == 0 { + return nil, fmt.Errorf("signature is not in the correct subgroup") + } + + return &Signature{Value: *sig}, nil +} + +// Ensure no duplicates x values and convert x values to field elements +func splitXY(partials []*PartialSignature) ([]*native.Field, []*bls12381.G2, error) { + x := make([]*native.Field, len(partials)) + y := make([]*bls12381.G2, len(partials)) + + dup := make(map[byte]bool) + + for i, sp := range partials { + if sp == nil { + return nil, nil, fmt.Errorf("partial signature cannot be nil") + } + if _, exists := dup[sp.Identifier]; exists { + return nil, nil, fmt.Errorf("duplicate signature included") + } + if sp.Signature.InCorrectSubgroup() == 0 { + return nil, nil, fmt.Errorf("signature is not in the correct subgroup") + } + dup[sp.Identifier] = true + x[i] = bls12381.Bls12381FqNew().SetUint64(uint64(sp.Identifier)) + y[i] = &sp.Signature + } + return x, y, nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/LICENSE b/vendor/github.com/consensys/gnark-crypto/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go new file mode 100644 index 0000000000..e6dce675a3 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go @@ -0,0 +1,128 @@ +package bls12377 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +// E: y**2=x**3+1 +// Etwist: y**2 = x**3+u**-1 +// Tower: Fp->Fp2, u**2=-5 -> Fp12, v**6=u +// Generator (BLS12 family): x=9586122913090633729 +// optimal Ate loop: trace(frob)-1=x +// trace of pi: x+1 +// Fp: p=258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +// Fr: r=8444461749428370424248824938781546531375899335154063827935233455917409239041 (x**4-x**2+1) + +// ID bls377 ID +const ID = ecc.BLS12_377 + +// bCurveCoeff b coeff of the curve +var bCurveCoeff fp.Element + +// twist +var twist fptower.E2 + +// bTwistCurveCoeff b coeff of the twist (defined over Fp2) curve +var bTwistCurveCoeff fptower.E2 + +// generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +var g1Gen G1Jac +var g2Gen G2Jac + +var g1GenAff G1Affine +var g2GenAff G2Affine + +// point at infinity +var g1Infinity G1Jac +var g2Infinity G2Jac + +// optimal Ate loop counter (=trace-1 = x in BLS family) +var loopCounter [64]int8 + +// Parameters useful for the GLV scalar multiplication. The third roots define the +// endomorphisms phi1 and phi2 for and . lambda is such that lies above +// in the ring Z[phi]. More concretely it's the associated eigenvalue +// of phi1 (resp phi2) restricted to (resp ) +// cf https://www.cosic.esat.kuleuven.be/nessie/reports/phase2/GLV.pdf +var thirdRootOneG1 fp.Element +var thirdRootOneG2 fp.Element +var lambdaGLV big.Int + +// glvBasis stores R-linearly independant vectors (a,b), (c,d) +// in ker((u,v)->u+vlambda[r]), and their determinant +var glvBasis ecc.Lattice + +// psi o pi o psi**-1, where psi:E->E' is the degree 6 iso defined over Fp12 +var endo struct { + u fptower.E2 + v fptower.E2 +} + +// generator of the curve +var xGen big.Int + +// expose the tower -- github.com/consensys/gnark uses it in a gnark circuit + +// E2 is a degree two finite field extension of fp.Element +type E2 = fptower.E2 + +// E6 is a degree three finite field extension of fp2 +type E6 = fptower.E6 + +// E12 is a degree two finite field extension of fp6 +type E12 = fptower.E12 + +func init() { + + bCurveCoeff.SetUint64(1) + twist.A1.SetUint64(1) + bTwistCurveCoeff.Inverse(&twist) + + g1Gen.X.SetString("81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695") + g1Gen.Y.SetString("241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030") + g1Gen.Z.SetString("1") + + g2Gen.X.SetString("233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294", + "140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118") + g2Gen.Y.SetString("63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423", + "149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491") + g2Gen.Z.SetString("1", + "0") + + g1GenAff.FromJacobian(&g1Gen) + g2GenAff.FromJacobian(&g2Gen) + + g1Infinity.X.SetOne() + g1Infinity.Y.SetOne() + g2Infinity.X.SetOne() + g2Infinity.Y.SetOne() + + thirdRootOneG1.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945") + thirdRootOneG2.Square(&thirdRootOneG1) + lambdaGLV.SetString("91893752504881257701523279626832445440", 10) //(x**2-1) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + + endo.u.A0.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946") + endo.v.A0.SetString("216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499") + + // binary decomposition of 15132376222941642752 little endian + loopCounter = [64]int8{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1} + + xGen.SetString("9586122913090633729", 10) + +} + +// Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +func Generators() (g1Jac G1Jac, g2Jac G2Jac, g1Aff G1Affine, g2Aff G2Affine) { + g1Aff = g1GenAff + g2Aff = g2GenAff + g1Jac = g1Gen + g2Jac = g2Gen + return +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/doc.go new file mode 100644 index 0000000000..562982cc7e --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/doc.go @@ -0,0 +1,18 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package bls12377 efficient elliptic curve and pairing implementation for bls12-377. +package bls12377 diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go new file mode 100644 index 0000000000..66fa667482 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go @@ -0,0 +1,60 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go new file mode 100644 index 0000000000..7344271ebe --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go @@ -0,0 +1,24 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import "golang.org/x/sys/cpu" + +var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go new file mode 100644 index 0000000000..ae778bd3a1 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go @@ -0,0 +1,25 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go new file mode 100644 index 0000000000..d14a2fc3d2 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fp contains field arithmetic operations for modulus = 0x1ae3a4...000001. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@zkteam/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// type Element [6]uint64 +// +// Example API signature +// // Mul z = x * y mod q +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus +// 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 // base 16 +// 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 // base 10 +package fp diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go new file mode 100644 index 0000000000..574d740fc8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go @@ -0,0 +1,1208 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "sync" +) + +// Element represents a field element stored on 6 words (uint64) +// Element are assumed to be in Montgomery form in all methods +// field modulus q = +// +// 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +type Element [6]uint64 + +// Limbs number of 64 bits words needed to represent Element +const Limbs = 6 + +// Bits number bits needed to represent Element +const Bits = 377 + +// Bytes number bytes needed to represent Element +const Bytes = Limbs * 8 + +// field modulus stored as big.Int +var _modulus big.Int + +// Modulus returns q as a big.Int +// q = +// +// 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q (modulus) +var qElement = Element{ + 9586122913090633729, + 1660523435060625408, + 2230234197602682880, + 1883307231910630287, + 14284016967150029115, + 121098312706494698, +} + +// rSquare +var rSquare = Element{ + 13224372171368877346, + 227991066186625457, + 2496666625421784173, + 13825906835078366124, + 9475172226622360569, + 30958721782860680, +} + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +func init() { + _modulus.SetString("258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", 10) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// var v NewElement +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 z = v, sets z LSB to v (non-Montgomery form) and convert z to Montgomery form +func (z *Element) SetUint64(v uint64) *Element { + *z = Element{v} + return z.Mul(z, &rSquare) // z.ToMont() +} + +// Set z = x +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + z[4] = x[4] + z[5] = x[5] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: Element, *Element, uint64, int, string (interpreted as base10 integer), +// *big.Int, big.Int, []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + return z.Set(c1), nil + case uint64: + return z.SetUint64(c1), nil + case int: + return z.SetString(strconv.Itoa(c1)), nil + case string: + return z.SetString(c1), nil + case *big.Int: + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fp.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + z[4] = 0 + z[5] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 202099033278250856 + z[1] = 5854854902718660529 + z[2] = 11492539364873682930 + z[3] = 8885205928937022213 + z[4] = 5545221690922665192 + z[5] = 39800542322357402 + return z +} + +// Div z = x*y^-1 mod q +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Bit returns the i'th bit, with lsb == bit 0. +// It is the responsability of the caller to convert from Montgomery to Regular form if needed +func (z *Element) Bit(i uint64) uint64 { + j := i / 64 + if j >= 6 { + return 0 + } + return uint64(z[j] >> (i % 64) & 1) +} + +// Equal returns z == x +func (z *Element) Equal(x *Element) bool { + return (z[5] == x[5]) && (z[4] == x[4]) && (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsUint64 returns true if z[0] >= 0 and all other words are 0 +func (z *Element) IsUint64() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +// +func (z *Element) Cmp(x *Element) int { + _z := *z + _x := *x + _z.FromMont() + _x.FromMont() + if _z[5] > _x[5] { + return 1 + } else if _z[5] < _x[5] { + return -1 + } + if _z[4] > _x[4] { + return 1 + } else if _z[4] < _x[4] { + return -1 + } + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := *z + _z.FromMont() + + var b uint64 + _, b = bits.Sub64(_z[0], 4793061456545316865, 0) + _, b = bits.Sub64(_z[1], 830261717530312704, b) + _, b = bits.Sub64(_z[2], 10338489135656117248, b) + _, b = bits.Sub64(_z[3], 10165025652810090951, b) + _, b = bits.Sub64(_z[4], 7142008483575014557, b) + _, b = bits.Sub64(_z[5], 60549156353247349, b) + + return b == 0 +} + +// SetRandom sets z to a random element < q +func (z *Element) SetRandom() (*Element, error) { + var bytes [48]byte + if _, err := io.ReadFull(rand.Reader, bytes[:]); err != nil { + return nil, err + } + z[0] = binary.BigEndian.Uint64(bytes[0:8]) + z[1] = binary.BigEndian.Uint64(bytes[8:16]) + z[2] = binary.BigEndian.Uint64(bytes[16:24]) + z[3] = binary.BigEndian.Uint64(bytes[24:32]) + z[4] = binary.BigEndian.Uint64(bytes[32:40]) + z[5] = binary.BigEndian.Uint64(bytes[40:48]) + z[5] %= 121098312706494698 + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } + + return z, nil +} + +// One returns 1 (in montgommery form) +func One() Element { + var one Element + one.SetOne() + return one +} + +// Halve sets z to z / 2 (mod p) +func (z *Element) Halve() { + if z[0]&1 == 1 { + var carry uint64 + + // z = z + q + z[0], carry = bits.Add64(z[0], 9586122913090633729, 0) + z[1], carry = bits.Add64(z[1], 1660523435060625408, carry) + z[2], carry = bits.Add64(z[2], 2230234197602682880, carry) + z[3], carry = bits.Add64(z[3], 1883307231910630287, carry) + z[4], carry = bits.Add64(z[4], 14284016967150029115, carry) + z[5], _ = bits.Add64(z[5], 121098312706494698, carry) + + } + + // z = z >> 1 + + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] = z[3]>>1 | z[4]<<63 + z[4] = z[4]>>1 | z[5]<<63 + z[5] >>= 1 + +} + +// API with assembly impl + +// Mul z = x * y mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *Element) Mul(x, y *Element) *Element { + mul(z, x, y) + return z +} + +// Square z = x * x mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *Element) Square(x *Element) *Element { + mul(z, x, x) + return z +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) FromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y mod q +func (z *Element) Add(x, y *Element) *Element { + add(z, x, y) + return z +} + +// Double z = x + x mod q, aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + double(z, x) + return z +} + +// Sub z = x - y mod q +func (z *Element) Sub(x, y *Element) *Element { + sub(z, x, y) + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + neg(z, x) + return z +} + +// Generic (no ADX instructions, no AMD64) versions of multiplication and squaring algorithms + +func _mulGeneric(z, x, y *Element) { + + var t [6]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, y[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd1(v, y[1], c[1]) + c[2], t[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd1(v, y[2], c[1]) + c[2], t[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd1(v, y[3], c[1]) + c[2], t[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd1(v, y[4], c[1]) + c[2], t[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd1(v, y[5], c[1]) + t[5], t[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + { + // round 4 + v := x[4] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + { + // round 5 + v := x[5] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9586122913090633727 + c[2] = madd0(m, 9586122913090633729, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], z[0] = madd2(m, 1660523435060625408, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], z[1] = madd2(m, 2230234197602682880, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], z[2] = madd2(m, 1883307231910630287, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], z[3] = madd2(m, 14284016967150029115, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + z[5], z[4] = madd3(m, 121098312706494698, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 9586122913090633727 + C := madd0(m, 9586122913090633729, z[0]) + C, z[0] = madd2(m, 1660523435060625408, z[1], C) + C, z[1] = madd2(m, 2230234197602682880, z[2], C) + C, z[2] = madd2(m, 1883307231910630287, z[3], C) + C, z[3] = madd2(m, 14284016967150029115, z[4], C) + C, z[4] = madd2(m, 121098312706494698, z[5], C) + z[5] = C + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } +} + +func _addGeneric(z, x, y *Element) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], carry = bits.Add64(x[3], y[3], carry) + z[4], carry = bits.Add64(x[4], y[4], carry) + z[5], _ = bits.Add64(x[5], y[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } +} + +func _doubleGeneric(z, x *Element) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], carry = bits.Add64(x[3], x[3], carry) + z[4], carry = bits.Add64(x[4], x[4], carry) + z[5], _ = bits.Add64(x[5], x[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } +} + +func _subGeneric(z, x, y *Element) { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + z[4], b = bits.Sub64(x[4], y[4], b) + z[5], b = bits.Sub64(x[5], y[5], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], 9586122913090633729, 0) + z[1], c = bits.Add64(z[1], 1660523435060625408, c) + z[2], c = bits.Add64(z[2], 2230234197602682880, c) + z[3], c = bits.Add64(z[3], 1883307231910630287, c) + z[4], c = bits.Add64(z[4], 14284016967150029115, c) + z[5], _ = bits.Add64(z[5], 121098312706494698, c) + } +} + +func _negGeneric(z, x *Element) { + if x.IsZero() { + z.SetZero() + return + } + var borrow uint64 + z[0], borrow = bits.Sub64(9586122913090633729, x[0], 0) + z[1], borrow = bits.Sub64(1660523435060625408, x[1], borrow) + z[2], borrow = bits.Sub64(2230234197602682880, x[2], borrow) + z[3], borrow = bits.Sub64(1883307231910630287, x[3], borrow) + z[4], borrow = bits.Sub64(14284016967150029115, x[4], borrow) + z[5], _ = bits.Sub64(121098312706494698, x[5], borrow) +} + +func _reduceGeneric(z *Element) { + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 121098312706494698 || (z[5] == 121098312706494698 && (z[4] < 14284016967150029115 || (z[4] == 14284016967150029115 && (z[3] < 1883307231910630287 || (z[3] == 1883307231910630287 && (z[2] < 2230234197602682880 || (z[2] == 2230234197602682880 && (z[1] < 1660523435060625408 || (z[1] == 1660523435060625408 && (z[0] < 9586122913090633729))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 9586122913090633729, 0) + z[1], b = bits.Sub64(z[1], 1660523435060625408, b) + z[2], b = bits.Sub64(z[2], 2230234197602682880, b) + z[3], b = bits.Sub64(z[3], 1883307231910630287, b) + z[4], b = bits.Sub64(z[4], 14284016967150029115, b) + z[5], _ = bits.Sub64(z[5], 121098312706494698, b) + } +} + +func mulByConstant(z *Element, c uint8) { + switch c { + case 0: + z.SetZero() + return + case 1: + return + case 2: + z.Double(z) + return + case 3: + _z := *z + z.Double(z).Add(z, &_z) + case 5: + _z := *z + z.Double(z).Double(z).Add(z, &_z) + default: + var y Element + y.SetUint64(uint64(c)) + z.Mul(z, &y) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[5] != 0 { + return 320 + bits.Len64(z[5]) + } + if z[4] != 0 { + return 256 + bits.Len64(z[4]) + } + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Exp z = x^exponent mod q +func (z *Element) Exp(x Element, exponent *big.Int) *Element { + var bZero big.Int + if exponent.Cmp(&bZero) == 0 { + return z.SetOne() + } + + z.Set(&x) + + for i := exponent.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if exponent.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// ToMont converts z to Montgomery form +// sets and returns z = z * r^2 +func (z *Element) ToMont() *Element { + return z.Mul(z, &rSquare) +} + +// ToRegular returns z in regular form (doesn't mutate z) +func (z Element) ToRegular() Element { + return *z.FromMont() +} + +// String returns the string form of an Element in Montgomery form +func (z *Element) String() string { + zz := *z + zz.FromMont() + if zz.IsUint64() { + return strconv.FormatUint(zz[0], 10) + } else { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.FromMont() + if zzNeg.IsUint64() { + return "-" + strconv.FormatUint(zzNeg[0], 10) + } + } + vv := bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(vv) + return zz.ToBigInt(vv).String() +} + +// ToBigInt returns z as a big.Int in Montgomery form +func (z *Element) ToBigInt(res *big.Int) *big.Int { + var b [Limbs * 8]byte + binary.BigEndian.PutUint64(b[40:48], z[0]) + binary.BigEndian.PutUint64(b[32:40], z[1]) + binary.BigEndian.PutUint64(b[24:32], z[2]) + binary.BigEndian.PutUint64(b[16:24], z[3]) + binary.BigEndian.PutUint64(b[8:16], z[4]) + binary.BigEndian.PutUint64(b[0:8], z[5]) + + return res.SetBytes(b[:]) +} + +// ToBigIntRegular returns z as a big.Int in regular form +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.FromMont() + return z.ToBigInt(res) +} + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +func (z *Element) Bytes() (res [Limbs * 8]byte) { + _z := z.ToRegular() + binary.BigEndian.PutUint64(res[40:48], _z[0]) + binary.BigEndian.PutUint64(res[32:40], _z[1]) + binary.BigEndian.PutUint64(res[24:32], _z[2]) + binary.BigEndian.PutUint64(res[16:24], _z[3]) + binary.BigEndian.PutUint64(res[8:16], _z[4]) + binary.BigEndian.PutUint64(res[0:8], _z[5]) + + return +} + +// Marshal returns the regular (non montgomery) value +// of z as a big-endian byte slice. +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value (in Montgomery form), and returns z. +func (z *Element) SetBytes(e []byte) *Element { + // get a big int from our pool + vv := bigIntPool.Get().(*big.Int) + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + bigIntPool.Put(vv) + + return z +} + +// SetBigInt sets z to v (regular form) and returns z in Montgomery form +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + // copy input + modular reduction + vv.Set(v) + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + return z +} + +// setBigInt assumes 0 <= v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.ToMont() +} + +// SetString creates a big.Int with s (in base 10) and calls SetBigInt on z +func (z *Element) SetString(s string) *Element { + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + if _, ok := vv.SetString(s, 10); !ok { + panic("Element.SetString failed -> can't parse number in base10 into a big.Int") + } + z.SetBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + + return z +} + +var ( + _bLegendreExponentElement *big.Int + _bSqrtExponentElement *big.Int +) + +func init() { + _bLegendreExponentElement, _ = new(big.Int).SetString("d71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117dd04a4000b85aea2180000004284600000000000", 16) + const sqrtExponentElement = "35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11" + _bSqrtExponentElement, _ = new(big.Int).SetString(sqrtExponentElement, 16) +} + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.Exp(*z, _bLegendreExponentElement) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if (l[5] == 39800542322357402) && (l[4] == 5545221690922665192) && (l[3] == 8885205928937022213) && (l[2] == 11492539364873682930) && (l[1] == 5854854902718660529) && (l[0] == 202099033278250856) { + return 1 + } + return -1 +} + +// Sqrt z = √x mod q +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b, t, w Element + // w = x^((s-1)/2)) + w.Exp(*x, _bSqrtExponentElement) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = x^s = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = Element{ + 7563926049028936178, + 2688164645460651601, + 12112688591437172399, + 3177973240564633687, + 14764383749841851163, + 52487407124055189, + } + r := uint64(46) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of x^s + t = b + for i := uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !((t[5] == 39800542322357402) && (t[4] == 5545221690922665192) && (t[3] == 8885205928937022213) && (t[2] == 11492539364873682930) && (t[1] == 5854854902718660529) && (t[0] == 202099033278250856)) { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !((t[5] == 39800542322357402) && (t[4] == 5545221690922665192) && (t[3] == 8885205928937022213) && (t[2] == 11492539364873682930) && (t[1] == 5854854902718660529) && (t[0] == 202099033278250856)) { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) mod q + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } +} + +// Inverse z = x^-1 mod q +// Algorithm 16 in "Efficient Software-Implementation of Finite Fields with Applications to Cryptography" +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + + // initialize u = q + var u = Element{ + 9586122913090633729, + 1660523435060625408, + 2230234197602682880, + 1883307231910630287, + 14284016967150029115, + 121098312706494698, + } + + // initialize s = r^2 + var s = Element{ + 13224372171368877346, + 227991066186625457, + 2496666625421784173, + 13825906835078366124, + 9475172226622360569, + 30958721782860680, + } + + // r = 0 + r := Element{} + + v := *x + + var carry, borrow uint64 + var bigger bool + + for { + for v[0]&1 == 0 { + + // v = v >> 1 + + v[0] = v[0]>>1 | v[1]<<63 + v[1] = v[1]>>1 | v[2]<<63 + v[2] = v[2]>>1 | v[3]<<63 + v[3] = v[3]>>1 | v[4]<<63 + v[4] = v[4]>>1 | v[5]<<63 + v[5] >>= 1 + + if s[0]&1 == 1 { + + // s = s + q + s[0], carry = bits.Add64(s[0], 9586122913090633729, 0) + s[1], carry = bits.Add64(s[1], 1660523435060625408, carry) + s[2], carry = bits.Add64(s[2], 2230234197602682880, carry) + s[3], carry = bits.Add64(s[3], 1883307231910630287, carry) + s[4], carry = bits.Add64(s[4], 14284016967150029115, carry) + s[5], _ = bits.Add64(s[5], 121098312706494698, carry) + + } + + // s = s >> 1 + + s[0] = s[0]>>1 | s[1]<<63 + s[1] = s[1]>>1 | s[2]<<63 + s[2] = s[2]>>1 | s[3]<<63 + s[3] = s[3]>>1 | s[4]<<63 + s[4] = s[4]>>1 | s[5]<<63 + s[5] >>= 1 + + } + for u[0]&1 == 0 { + + // u = u >> 1 + + u[0] = u[0]>>1 | u[1]<<63 + u[1] = u[1]>>1 | u[2]<<63 + u[2] = u[2]>>1 | u[3]<<63 + u[3] = u[3]>>1 | u[4]<<63 + u[4] = u[4]>>1 | u[5]<<63 + u[5] >>= 1 + + if r[0]&1 == 1 { + + // r = r + q + r[0], carry = bits.Add64(r[0], 9586122913090633729, 0) + r[1], carry = bits.Add64(r[1], 1660523435060625408, carry) + r[2], carry = bits.Add64(r[2], 2230234197602682880, carry) + r[3], carry = bits.Add64(r[3], 1883307231910630287, carry) + r[4], carry = bits.Add64(r[4], 14284016967150029115, carry) + r[5], _ = bits.Add64(r[5], 121098312706494698, carry) + + } + + // r = r >> 1 + + r[0] = r[0]>>1 | r[1]<<63 + r[1] = r[1]>>1 | r[2]<<63 + r[2] = r[2]>>1 | r[3]<<63 + r[3] = r[3]>>1 | r[4]<<63 + r[4] = r[4]>>1 | r[5]<<63 + r[5] >>= 1 + + } + + // v >= u + bigger = !(v[5] < u[5] || (v[5] == u[5] && (v[4] < u[4] || (v[4] == u[4] && (v[3] < u[3] || (v[3] == u[3] && (v[2] < u[2] || (v[2] == u[2] && (v[1] < u[1] || (v[1] == u[1] && (v[0] < u[0]))))))))))) + + if bigger { + + // v = v - u + v[0], borrow = bits.Sub64(v[0], u[0], 0) + v[1], borrow = bits.Sub64(v[1], u[1], borrow) + v[2], borrow = bits.Sub64(v[2], u[2], borrow) + v[3], borrow = bits.Sub64(v[3], u[3], borrow) + v[4], borrow = bits.Sub64(v[4], u[4], borrow) + v[5], _ = bits.Sub64(v[5], u[5], borrow) + + // s = s - r + s[0], borrow = bits.Sub64(s[0], r[0], 0) + s[1], borrow = bits.Sub64(s[1], r[1], borrow) + s[2], borrow = bits.Sub64(s[2], r[2], borrow) + s[3], borrow = bits.Sub64(s[3], r[3], borrow) + s[4], borrow = bits.Sub64(s[4], r[4], borrow) + s[5], borrow = bits.Sub64(s[5], r[5], borrow) + + if borrow == 1 { + + // s = s + q + s[0], carry = bits.Add64(s[0], 9586122913090633729, 0) + s[1], carry = bits.Add64(s[1], 1660523435060625408, carry) + s[2], carry = bits.Add64(s[2], 2230234197602682880, carry) + s[3], carry = bits.Add64(s[3], 1883307231910630287, carry) + s[4], carry = bits.Add64(s[4], 14284016967150029115, carry) + s[5], _ = bits.Add64(s[5], 121098312706494698, carry) + + } + } else { + + // u = u - v + u[0], borrow = bits.Sub64(u[0], v[0], 0) + u[1], borrow = bits.Sub64(u[1], v[1], borrow) + u[2], borrow = bits.Sub64(u[2], v[2], borrow) + u[3], borrow = bits.Sub64(u[3], v[3], borrow) + u[4], borrow = bits.Sub64(u[4], v[4], borrow) + u[5], _ = bits.Sub64(u[5], v[5], borrow) + + // r = r - s + r[0], borrow = bits.Sub64(r[0], s[0], 0) + r[1], borrow = bits.Sub64(r[1], s[1], borrow) + r[2], borrow = bits.Sub64(r[2], s[2], borrow) + r[3], borrow = bits.Sub64(r[3], s[3], borrow) + r[4], borrow = bits.Sub64(r[4], s[4], borrow) + r[5], borrow = bits.Sub64(r[5], s[5], borrow) + + if borrow == 1 { + + // r = r + q + r[0], carry = bits.Add64(r[0], 9586122913090633729, 0) + r[1], carry = bits.Add64(r[1], 1660523435060625408, carry) + r[2], carry = bits.Add64(r[2], 2230234197602682880, carry) + r[3], carry = bits.Add64(r[3], 1883307231910630287, carry) + r[4], carry = bits.Add64(r[4], 14284016967150029115, carry) + r[5], _ = bits.Add64(r[5], 121098312706494698, carry) + + } + } + if (u[0] == 1) && (u[5]|u[4]|u[3]|u[2]|u[1]) == 0 { + z.Set(&r) + return z + } + if (v[0] == 1) && (v[5]|v[4]|v[3]|v[2]|v[1]) == 0 { + z.Set(&s) + return z + } + } + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_fuzz.go new file mode 100644 index 0000000000..0d948021ac --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_fuzz.go @@ -0,0 +1,152 @@ +//go:build gofuzz +// +build gofuzz + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "bytes" + "encoding/binary" + "io" + "math/big" + "math/bits" +) + +const ( + fuzzInteresting = 1 + fuzzNormal = 0 + fuzzDiscard = -1 +) + +// Fuzz arithmetic operations fuzzer +func Fuzz(data []byte) int { + r := bytes.NewReader(data) + + var e1, e2 Element + e1.SetRawBytes(r) + e2.SetRawBytes(r) + + { + // mul assembly + + var c, _c Element + a, _a, b, _b := e1, e1, e2, e2 + c.Mul(&a, &b) + _mulGeneric(&_c, &_a, &_b) + + if !c.Equal(&_c) { + panic("mul asm != mul generic on Element") + } + } + + { + // inverse + inv := e1 + inv.Inverse(&inv) + + var bInv, b1, b2 big.Int + e1.ToBigIntRegular(&b1) + bInv.ModInverse(&b1, Modulus()) + inv.ToBigIntRegular(&b2) + + if b2.Cmp(&bInv) != 0 { + panic("inverse operation doesn't match big int result") + } + } + + { + // a + -a == 0 + a, b := e1, e1 + b.Neg(&b) + a.Add(&a, &b) + if !a.IsZero() { + panic("a + -a != 0") + } + } + + return fuzzNormal + +} + +// SetRawBytes reads up to Bytes (bytes needed to represent Element) from reader +// and interpret it as big endian uint64 +// used for fuzzing purposes only +func (z *Element) SetRawBytes(r io.Reader) { + + buf := make([]byte, 8) + + for i := 0; i < len(z); i++ { + if _, err := io.ReadFull(r, buf); err != nil { + goto eof + } + z[i] = binary.BigEndian.Uint64(buf[:]) + } +eof: + z[5] %= qElement[5] + + if z.BiggerModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], qElement[0], 0) + z[1], b = bits.Sub64(z[1], qElement[1], b) + z[2], b = bits.Sub64(z[2], qElement[2], b) + z[3], b = bits.Sub64(z[3], qElement[3], b) + z[4], b = bits.Sub64(z[4], qElement[4], b) + z[5], b = bits.Sub64(z[5], qElement[5], b) + } + + return +} + +func (z *Element) BiggerModulus() bool { + if z[5] > qElement[5] { + return true + } + if z[5] < qElement[5] { + return false + } + + if z[4] > qElement[4] { + return true + } + if z[4] < qElement[4] { + return false + } + + if z[3] > qElement[3] { + return true + } + if z[3] < qElement[3] { + return false + } + + if z[2] > qElement[2] { + return true + } + if z[2] < qElement[2] { + return false + } + + if z[1] > qElement[1] { + return true + } + if z[1] < qElement[1] { + return false + } + + return z[0] >= qElement[0] +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_adx_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_adx_amd64.s new file mode 100644 index 0000000000..ff23c655b8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_adx_amd64.s @@ -0,0 +1,836 @@ +// +build amd64_adx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), NOSPLIT, $0-24 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + MOVQ x+8(FP), R8 + + // x[0] -> R10 + // x[1] -> R11 + // x[2] -> R12 + MOVQ 0(R8), R10 + MOVQ 8(R8), R11 + MOVQ 16(R8), R12 + MOVQ y+16(FP), R13 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // t[4] -> SI + // t[5] -> DI + // clear the flags + XORQ AX, AX + MOVQ 0(R13), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R10, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R11, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R12, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ 24(R8), AX, SI + ADOXQ AX, BX + + // (A,t[4]) := x[4]*y[0] + A + MULXQ 32(R8), AX, DI + ADOXQ AX, SI + + // (A,t[5]) := x[5]*y[0] + A + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 8(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 16(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 24(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 32(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 40(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R9,R8,R13,R10,R11,R12) + REDUCE(R14,R15,CX,BX,SI,DI,R9,R8,R13,R10,R11,R12) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +TEXT ·fromMont(SB), NOSPLIT, $0-8 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + MOVQ 32(DX), SI + MOVQ 40(DX), DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R8,R9,R10,R11,R12,R13) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s new file mode 100644 index 0000000000..dee1e1590b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s @@ -0,0 +1,858 @@ +// +build !amd64_adx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), $24-24 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 + MOVQ x+8(FP), R8 + + // x[0] -> R10 + // x[1] -> R11 + // x[2] -> R12 + MOVQ 0(R8), R10 + MOVQ 8(R8), R11 + MOVQ 16(R8), R12 + MOVQ y+16(FP), R13 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // t[4] -> SI + // t[5] -> DI + // clear the flags + XORQ AX, AX + MOVQ 0(R13), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R10, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R11, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R12, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ 24(R8), AX, SI + ADOXQ AX, BX + + // (A,t[4]) := x[4]*y[0] + A + MULXQ 32(R8), AX, DI + ADOXQ AX, SI + + // (A,t[5]) := x[5]*y[0] + A + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 8(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 16(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 24(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 32(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 40(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R9,R8,R13,R10,R11,R12) + REDUCE(R14,R15,CX,BX,SI,DI,R9,R8,R13,R10,R11,R12) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + MOVQ 32(DX), SI + MOVQ 40(DX), DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R8,R9,R10,R11,R12,R13) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go new file mode 100644 index 0000000000..73a3711ec0 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go @@ -0,0 +1,50 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func add(res, x, y *Element) + +//go:noescape +func sub(res, x, y *Element) + +//go:noescape +func neg(res, x *Element) + +//go:noescape +func double(res, x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +//go:noescape +func Butterfly(a, b *Element) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s new file mode 100644 index 0000000000..596b552dd0 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s @@ -0,0 +1,452 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +// add(res, x, y *Element) +TEXT ·add(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + MOVQ y+16(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + ADCQ 32(DX), R8 + ADCQ 40(DX), R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ res+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + MOVQ R8, 32(AX) + MOVQ R9, 40(AX) + RET + +// sub(res, x, y *Element) +TEXT ·sub(SB), NOSPLIT, $0-24 + XORQ R9, R9 + MOVQ x+8(FP), R8 + MOVQ 0(R8), AX + MOVQ 8(R8), DX + MOVQ 16(R8), CX + MOVQ 24(R8), BX + MOVQ 32(R8), SI + MOVQ 40(R8), DI + MOVQ y+16(FP), R8 + SUBQ 0(R8), AX + SBBQ 8(R8), DX + SBBQ 16(R8), CX + SBBQ 24(R8), BX + SBBQ 32(R8), SI + SBBQ 40(R8), DI + MOVQ $0x8508c00000000001, R10 + MOVQ $0x170b5d4430000000, R11 + MOVQ $0x1ef3622fba094800, R12 + MOVQ $0x1a22d9f300f5138f, R13 + MOVQ $0xc63b05c06ca1493b, R14 + MOVQ $0x01ae3a4617c510ea, R15 + CMOVQCC R9, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + ADDQ R10, AX + ADCQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + ADCQ R15, DI + MOVQ res+0(FP), R8 + MOVQ AX, 0(R8) + MOVQ DX, 8(R8) + MOVQ CX, 16(R8) + MOVQ BX, 24(R8) + MOVQ SI, 32(R8) + MOVQ DI, 40(R8) + RET + +// double(res, x *Element) +TEXT ·double(SB), NOSPLIT, $0-16 + MOVQ x+8(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ res+0(FP), R15 + MOVQ DX, 0(R15) + MOVQ CX, 8(R15) + MOVQ BX, 16(R15) + MOVQ SI, 24(R15) + MOVQ DI, 32(R15) + MOVQ R8, 40(R15) + RET + +// neg(res, x *Element) +TEXT ·neg(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), R9 + MOVQ x+8(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + MOVQ DX, AX + ORQ CX, AX + ORQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + TESTQ AX, AX + JEQ l1 + MOVQ $0x8508c00000000001, R10 + SUBQ DX, R10 + MOVQ R10, 0(R9) + MOVQ $0x170b5d4430000000, R10 + SBBQ CX, R10 + MOVQ R10, 8(R9) + MOVQ $0x1ef3622fba094800, R10 + SBBQ BX, R10 + MOVQ R10, 16(R9) + MOVQ $0x1a22d9f300f5138f, R10 + SBBQ SI, R10 + MOVQ R10, 24(R9) + MOVQ $0xc63b05c06ca1493b, R10 + SBBQ DI, R10 + MOVQ R10, 32(R9) + MOVQ $0x01ae3a4617c510ea, R10 + SBBQ R8, R10 + MOVQ R10, 40(R9) + RET + +l1: + MOVQ AX, 0(R9) + MOVQ AX, 8(R9) + MOVQ AX, 16(R9) + MOVQ AX, 24(R9) + MOVQ AX, 32(R9) + MOVQ AX, 40(R9) + RET + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R14,R15,R9,R10,R11,R12) + REDUCE(DX,CX,BX,SI,DI,R8,R14,R15,R9,R10,R11,R12) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), $40-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + REDUCE(DX,CX,BX,SI,DI,R8,R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + + MOVQ DX, R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ R15, DX + ADCQ s0-8(SP), CX + ADCQ s1-16(SP), BX + ADCQ s2-24(SP), SI + ADCQ s3-32(SP), DI + ADCQ s4-40(SP), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), $48-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + MOVQ CX, R10 + MOVQ BX, R11 + MOVQ SI, R12 + MOVQ DI, R13 + MOVQ R8, R14 + MOVQ R9, R15 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + ADCQ 32(DX), R8 + ADCQ 40(DX), R9 + SUBQ 0(DX), R10 + SBBQ 8(DX), R11 + SBBQ 16(DX), R12 + SBBQ 24(DX), R13 + SBBQ 32(DX), R14 + SBBQ 40(DX), R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + MOVQ R9, s5-48(SP) + MOVQ $0x8508c00000000001, CX + MOVQ $0x170b5d4430000000, BX + MOVQ $0x1ef3622fba094800, SI + MOVQ $0x1a22d9f300f5138f, DI + MOVQ $0xc63b05c06ca1493b, R8 + MOVQ $0x01ae3a4617c510ea, R9 + CMOVQCC AX, CX + CMOVQCC AX, BX + CMOVQCC AX, SI + CMOVQCC AX, DI + CMOVQCC AX, R8 + CMOVQCC AX, R9 + ADDQ CX, R10 + ADCQ BX, R11 + ADCQ SI, R12 + ADCQ DI, R13 + ADCQ R8, R14 + ADCQ R9, R15 + MOVQ s0-8(SP), CX + MOVQ s1-16(SP), BX + MOVQ s2-24(SP), SI + MOVQ s3-32(SP), DI + MOVQ s4-40(SP), R8 + MOVQ s5-48(SP), R9 + MOVQ R10, 0(DX) + MOVQ R11, 8(DX) + MOVQ R12, 16(DX) + MOVQ R13, 24(DX) + MOVQ R14, 32(DX) + MOVQ R15, 40(DX) + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + MOVQ R8, 32(AX) + MOVQ R9, 40(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_noasm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_noasm.go new file mode 100644 index 0000000000..fec6289183 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_noasm.go @@ -0,0 +1,78 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +// MulBy3 x *= 3 +func MulBy3(x *Element) { + mulByConstant(x, 3) +} + +// MulBy5 x *= 5 +func MulBy5(x *Element) { + mulByConstant(x, 5) +} + +// MulBy13 x *= 13 +func MulBy13(x *Element) { + mulByConstant(x, 13) +} + +// Butterfly sets +// a = a + b +// b = a - b +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func mul(z, x, y *Element) { + _mulGeneric(z, x, y) +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func add(z, x, y *Element) { + _addGeneric(z, x, y) +} + +func double(z, x *Element) { + _doubleGeneric(z, x) +} + +func sub(z, x, y *Element) { + _subGeneric(z, x, y) +} + +func neg(z, x *Element) { + _negGeneric(z, x) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go new file mode 100644 index 0000000000..83c9fd9ef9 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go @@ -0,0 +1,60 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go new file mode 100644 index 0000000000..8241357c45 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go @@ -0,0 +1,24 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import "golang.org/x/sys/cpu" + +var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go new file mode 100644 index 0000000000..221beab937 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go @@ -0,0 +1,25 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go new file mode 100644 index 0000000000..06d4199338 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fr contains field arithmetic operations for modulus = 0x12ab65...000001. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@zkteam/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// type Element [4]uint64 +// +// Example API signature +// // Mul z = x * y mod q +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus +// 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 // base 16 +// 8444461749428370424248824938781546531375899335154063827935233455917409239041 // base 10 +package fr diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go new file mode 100644 index 0000000000..444d3c40c5 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go @@ -0,0 +1,1038 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "sync" +) + +// Element represents a field element stored on 4 words (uint64) +// Element are assumed to be in Montgomery form in all methods +// field modulus q = +// +// 8444461749428370424248824938781546531375899335154063827935233455917409239041 +type Element [4]uint64 + +// Limbs number of 64 bits words needed to represent Element +const Limbs = 4 + +// Bits number bits needed to represent Element +const Bits = 253 + +// Bytes number bytes needed to represent Element +const Bytes = Limbs * 8 + +// field modulus stored as big.Int +var _modulus big.Int + +// Modulus returns q as a big.Int +// q = +// +// 8444461749428370424248824938781546531375899335154063827935233455917409239041 +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q (modulus) +var qElement = Element{ + 725501752471715841, + 6461107452199829505, + 6968279316240510977, + 1345280370688173398, +} + +// rSquare +var rSquare = Element{ + 2726216793283724667, + 14712177743343147295, + 12091039717619697043, + 81024008013859129, +} + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +func init() { + _modulus.SetString("8444461749428370424248824938781546531375899335154063827935233455917409239041", 10) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// var v NewElement +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 z = v, sets z LSB to v (non-Montgomery form) and convert z to Montgomery form +func (z *Element) SetUint64(v uint64) *Element { + *z = Element{v} + return z.Mul(z, &rSquare) // z.ToMont() +} + +// Set z = x +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: Element, *Element, uint64, int, string (interpreted as base10 integer), +// *big.Int, big.Int, []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + return z.Set(c1), nil + case uint64: + return z.SetUint64(c1), nil + case int: + return z.SetString(strconv.Itoa(c1)), nil + case string: + return z.SetString(c1), nil + case *big.Int: + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fr.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 9015221291577245683 + z[1] = 8239323489949974514 + z[2] = 1646089257421115374 + z[3] = 958099254763297437 + return z +} + +// Div z = x*y^-1 mod q +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Bit returns the i'th bit, with lsb == bit 0. +// It is the responsability of the caller to convert from Montgomery to Regular form if needed +func (z *Element) Bit(i uint64) uint64 { + j := i / 64 + if j >= 4 { + return 0 + } + return uint64(z[j] >> (i % 64) & 1) +} + +// Equal returns z == x +func (z *Element) Equal(x *Element) bool { + return (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsUint64 returns true if z[0] >= 0 and all other words are 0 +func (z *Element) IsUint64() bool { + return (z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +// +func (z *Element) Cmp(x *Element) int { + _z := *z + _x := *x + _z.FromMont() + _x.FromMont() + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := *z + _z.FromMont() + + var b uint64 + _, b = bits.Sub64(_z[0], 9586122913090633729, 0) + _, b = bits.Sub64(_z[1], 12453925762954690560, b) + _, b = bits.Sub64(_z[2], 3484139658120255488, b) + _, b = bits.Sub64(_z[3], 672640185344086699, b) + + return b == 0 +} + +// SetRandom sets z to a random element < q +func (z *Element) SetRandom() (*Element, error) { + var bytes [32]byte + if _, err := io.ReadFull(rand.Reader, bytes[:]); err != nil { + return nil, err + } + z[0] = binary.BigEndian.Uint64(bytes[0:8]) + z[1] = binary.BigEndian.Uint64(bytes[8:16]) + z[2] = binary.BigEndian.Uint64(bytes[16:24]) + z[3] = binary.BigEndian.Uint64(bytes[24:32]) + z[3] %= 1345280370688173398 + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } + + return z, nil +} + +// One returns 1 (in montgommery form) +func One() Element { + var one Element + one.SetOne() + return one +} + +// Halve sets z to z / 2 (mod p) +func (z *Element) Halve() { + if z[0]&1 == 1 { + var carry uint64 + + // z = z + q + z[0], carry = bits.Add64(z[0], 725501752471715841, 0) + z[1], carry = bits.Add64(z[1], 6461107452199829505, carry) + z[2], carry = bits.Add64(z[2], 6968279316240510977, carry) + z[3], _ = bits.Add64(z[3], 1345280370688173398, carry) + + } + + // z = z >> 1 + + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] >>= 1 + +} + +// API with assembly impl + +// Mul z = x * y mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *Element) Mul(x, y *Element) *Element { + mul(z, x, y) + return z +} + +// Square z = x * x mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *Element) Square(x *Element) *Element { + mul(z, x, x) + return z +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) FromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y mod q +func (z *Element) Add(x, y *Element) *Element { + add(z, x, y) + return z +} + +// Double z = x + x mod q, aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + double(z, x) + return z +} + +// Sub z = x - y mod q +func (z *Element) Sub(x, y *Element) *Element { + sub(z, x, y) + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + neg(z, x) + return z +} + +// Generic (no ADX instructions, no AMD64) versions of multiplication and squaring algorithms + +func _mulGeneric(z, x, y *Element) { + + var t [4]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, y[0]) + m := c[0] * 725501752471715839 + c[2] = madd0(m, 725501752471715841, c[0]) + c[1], c[0] = madd1(v, y[1], c[1]) + c[2], t[0] = madd2(m, 6461107452199829505, c[2], c[0]) + c[1], c[0] = madd1(v, y[2], c[1]) + c[2], t[1] = madd2(m, 6968279316240510977, c[2], c[0]) + c[1], c[0] = madd1(v, y[3], c[1]) + t[3], t[2] = madd3(m, 1345280370688173398, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 725501752471715839 + c[2] = madd0(m, 725501752471715841, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6461107452199829505, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 6968279316240510977, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + t[3], t[2] = madd3(m, 1345280370688173398, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 725501752471715839 + c[2] = madd0(m, 725501752471715841, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6461107452199829505, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 6968279316240510977, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + t[3], t[2] = madd3(m, 1345280370688173398, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 725501752471715839 + c[2] = madd0(m, 725501752471715841, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], z[0] = madd2(m, 6461107452199829505, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], z[1] = madd2(m, 6968279316240510977, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + z[3], z[2] = madd3(m, 1345280370688173398, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + { + // m = z[0]n'[0] mod W + m := z[0] * 725501752471715839 + C := madd0(m, 725501752471715841, z[0]) + C, z[0] = madd2(m, 6461107452199829505, z[1], C) + C, z[1] = madd2(m, 6968279316240510977, z[2], C) + C, z[2] = madd2(m, 1345280370688173398, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 725501752471715839 + C := madd0(m, 725501752471715841, z[0]) + C, z[0] = madd2(m, 6461107452199829505, z[1], C) + C, z[1] = madd2(m, 6968279316240510977, z[2], C) + C, z[2] = madd2(m, 1345280370688173398, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 725501752471715839 + C := madd0(m, 725501752471715841, z[0]) + C, z[0] = madd2(m, 6461107452199829505, z[1], C) + C, z[1] = madd2(m, 6968279316240510977, z[2], C) + C, z[2] = madd2(m, 1345280370688173398, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * 725501752471715839 + C := madd0(m, 725501752471715841, z[0]) + C, z[0] = madd2(m, 6461107452199829505, z[1], C) + C, z[1] = madd2(m, 6968279316240510977, z[2], C) + C, z[2] = madd2(m, 1345280370688173398, z[3], C) + z[3] = C + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } +} + +func _addGeneric(z, x, y *Element) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } +} + +func _doubleGeneric(z, x *Element) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } +} + +func _subGeneric(z, x, y *Element) { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], 725501752471715841, 0) + z[1], c = bits.Add64(z[1], 6461107452199829505, c) + z[2], c = bits.Add64(z[2], 6968279316240510977, c) + z[3], _ = bits.Add64(z[3], 1345280370688173398, c) + } +} + +func _negGeneric(z, x *Element) { + if x.IsZero() { + z.SetZero() + return + } + var borrow uint64 + z[0], borrow = bits.Sub64(725501752471715841, x[0], 0) + z[1], borrow = bits.Sub64(6461107452199829505, x[1], borrow) + z[2], borrow = bits.Sub64(6968279316240510977, x[2], borrow) + z[3], _ = bits.Sub64(1345280370688173398, x[3], borrow) +} + +func _reduceGeneric(z *Element) { + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 1345280370688173398 || (z[3] == 1345280370688173398 && (z[2] < 6968279316240510977 || (z[2] == 6968279316240510977 && (z[1] < 6461107452199829505 || (z[1] == 6461107452199829505 && (z[0] < 725501752471715841))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 725501752471715841, 0) + z[1], b = bits.Sub64(z[1], 6461107452199829505, b) + z[2], b = bits.Sub64(z[2], 6968279316240510977, b) + z[3], _ = bits.Sub64(z[3], 1345280370688173398, b) + } +} + +func mulByConstant(z *Element, c uint8) { + switch c { + case 0: + z.SetZero() + return + case 1: + return + case 2: + z.Double(z) + return + case 3: + _z := *z + z.Double(z).Add(z, &_z) + case 5: + _z := *z + z.Double(z).Double(z).Add(z, &_z) + default: + var y Element + y.SetUint64(uint64(c)) + z.Mul(z, &y) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Exp z = x^exponent mod q +func (z *Element) Exp(x Element, exponent *big.Int) *Element { + var bZero big.Int + if exponent.Cmp(&bZero) == 0 { + return z.SetOne() + } + + z.Set(&x) + + for i := exponent.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if exponent.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// ToMont converts z to Montgomery form +// sets and returns z = z * r^2 +func (z *Element) ToMont() *Element { + return z.Mul(z, &rSquare) +} + +// ToRegular returns z in regular form (doesn't mutate z) +func (z Element) ToRegular() Element { + return *z.FromMont() +} + +// String returns the string form of an Element in Montgomery form +func (z *Element) String() string { + zz := *z + zz.FromMont() + if zz.IsUint64() { + return strconv.FormatUint(zz[0], 10) + } else { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.FromMont() + if zzNeg.IsUint64() { + return "-" + strconv.FormatUint(zzNeg[0], 10) + } + } + vv := bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(vv) + return zz.ToBigInt(vv).String() +} + +// ToBigInt returns z as a big.Int in Montgomery form +func (z *Element) ToBigInt(res *big.Int) *big.Int { + var b [Limbs * 8]byte + binary.BigEndian.PutUint64(b[24:32], z[0]) + binary.BigEndian.PutUint64(b[16:24], z[1]) + binary.BigEndian.PutUint64(b[8:16], z[2]) + binary.BigEndian.PutUint64(b[0:8], z[3]) + + return res.SetBytes(b[:]) +} + +// ToBigIntRegular returns z as a big.Int in regular form +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.FromMont() + return z.ToBigInt(res) +} + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +func (z *Element) Bytes() (res [Limbs * 8]byte) { + _z := z.ToRegular() + binary.BigEndian.PutUint64(res[24:32], _z[0]) + binary.BigEndian.PutUint64(res[16:24], _z[1]) + binary.BigEndian.PutUint64(res[8:16], _z[2]) + binary.BigEndian.PutUint64(res[0:8], _z[3]) + + return +} + +// Marshal returns the regular (non montgomery) value +// of z as a big-endian byte slice. +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value (in Montgomery form), and returns z. +func (z *Element) SetBytes(e []byte) *Element { + // get a big int from our pool + vv := bigIntPool.Get().(*big.Int) + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + bigIntPool.Put(vv) + + return z +} + +// SetBigInt sets z to v (regular form) and returns z in Montgomery form +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + // copy input + modular reduction + vv.Set(v) + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + return z +} + +// setBigInt assumes 0 <= v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.ToMont() +} + +// SetString creates a big.Int with s (in base 10) and calls SetBigInt on z +func (z *Element) SetString(s string) *Element { + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + if _, ok := vv.SetString(s, 10); !ok { + panic("Element.SetString failed -> can't parse number in base10 into a big.Int") + } + z.SetBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + + return z +} + +var ( + _bLegendreExponentElement *big.Int + _bSqrtExponentElement *big.Int +) + +func init() { + _bLegendreExponentElement, _ = new(big.Int).SetString("955b2af4d1652ab305a268f2e1bd800acd53b7f680000008508c00000000000", 16) + const sqrtExponentElement = "12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11" + _bSqrtExponentElement, _ = new(big.Int).SetString(sqrtExponentElement, 16) +} + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.Exp(*z, _bLegendreExponentElement) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if (l[3] == 958099254763297437) && (l[2] == 1646089257421115374) && (l[1] == 8239323489949974514) && (l[0] == 9015221291577245683) { + return 1 + } + return -1 +} + +// Sqrt z = √x mod q +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b, t, w Element + // w = x^((s-1)/2)) + w.Exp(*x, _bSqrtExponentElement) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = x^s = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = Element{ + 4340692304772210610, + 11102725085307959083, + 15540458298643990566, + 944526744080888988, + } + r := uint64(47) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of x^s + t = b + for i := uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !((t[3] == 958099254763297437) && (t[2] == 1646089257421115374) && (t[1] == 8239323489949974514) && (t[0] == 9015221291577245683)) { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !((t[3] == 958099254763297437) && (t[2] == 1646089257421115374) && (t[1] == 8239323489949974514) && (t[0] == 9015221291577245683)) { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) mod q + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } +} + +// Inverse z = x^-1 mod q +// Algorithm 16 in "Efficient Software-Implementation of Finite Fields with Applications to Cryptography" +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + + // initialize u = q + var u = Element{ + 725501752471715841, + 6461107452199829505, + 6968279316240510977, + 1345280370688173398, + } + + // initialize s = r^2 + var s = Element{ + 2726216793283724667, + 14712177743343147295, + 12091039717619697043, + 81024008013859129, + } + + // r = 0 + r := Element{} + + v := *x + + var carry, borrow uint64 + var bigger bool + + for { + for v[0]&1 == 0 { + + // v = v >> 1 + + v[0] = v[0]>>1 | v[1]<<63 + v[1] = v[1]>>1 | v[2]<<63 + v[2] = v[2]>>1 | v[3]<<63 + v[3] >>= 1 + + if s[0]&1 == 1 { + + // s = s + q + s[0], carry = bits.Add64(s[0], 725501752471715841, 0) + s[1], carry = bits.Add64(s[1], 6461107452199829505, carry) + s[2], carry = bits.Add64(s[2], 6968279316240510977, carry) + s[3], _ = bits.Add64(s[3], 1345280370688173398, carry) + + } + + // s = s >> 1 + + s[0] = s[0]>>1 | s[1]<<63 + s[1] = s[1]>>1 | s[2]<<63 + s[2] = s[2]>>1 | s[3]<<63 + s[3] >>= 1 + + } + for u[0]&1 == 0 { + + // u = u >> 1 + + u[0] = u[0]>>1 | u[1]<<63 + u[1] = u[1]>>1 | u[2]<<63 + u[2] = u[2]>>1 | u[3]<<63 + u[3] >>= 1 + + if r[0]&1 == 1 { + + // r = r + q + r[0], carry = bits.Add64(r[0], 725501752471715841, 0) + r[1], carry = bits.Add64(r[1], 6461107452199829505, carry) + r[2], carry = bits.Add64(r[2], 6968279316240510977, carry) + r[3], _ = bits.Add64(r[3], 1345280370688173398, carry) + + } + + // r = r >> 1 + + r[0] = r[0]>>1 | r[1]<<63 + r[1] = r[1]>>1 | r[2]<<63 + r[2] = r[2]>>1 | r[3]<<63 + r[3] >>= 1 + + } + + // v >= u + bigger = !(v[3] < u[3] || (v[3] == u[3] && (v[2] < u[2] || (v[2] == u[2] && (v[1] < u[1] || (v[1] == u[1] && (v[0] < u[0]))))))) + + if bigger { + + // v = v - u + v[0], borrow = bits.Sub64(v[0], u[0], 0) + v[1], borrow = bits.Sub64(v[1], u[1], borrow) + v[2], borrow = bits.Sub64(v[2], u[2], borrow) + v[3], _ = bits.Sub64(v[3], u[3], borrow) + + // s = s - r + s[0], borrow = bits.Sub64(s[0], r[0], 0) + s[1], borrow = bits.Sub64(s[1], r[1], borrow) + s[2], borrow = bits.Sub64(s[2], r[2], borrow) + s[3], borrow = bits.Sub64(s[3], r[3], borrow) + + if borrow == 1 { + + // s = s + q + s[0], carry = bits.Add64(s[0], 725501752471715841, 0) + s[1], carry = bits.Add64(s[1], 6461107452199829505, carry) + s[2], carry = bits.Add64(s[2], 6968279316240510977, carry) + s[3], _ = bits.Add64(s[3], 1345280370688173398, carry) + + } + } else { + + // u = u - v + u[0], borrow = bits.Sub64(u[0], v[0], 0) + u[1], borrow = bits.Sub64(u[1], v[1], borrow) + u[2], borrow = bits.Sub64(u[2], v[2], borrow) + u[3], _ = bits.Sub64(u[3], v[3], borrow) + + // r = r - s + r[0], borrow = bits.Sub64(r[0], s[0], 0) + r[1], borrow = bits.Sub64(r[1], s[1], borrow) + r[2], borrow = bits.Sub64(r[2], s[2], borrow) + r[3], borrow = bits.Sub64(r[3], s[3], borrow) + + if borrow == 1 { + + // r = r + q + r[0], carry = bits.Add64(r[0], 725501752471715841, 0) + r[1], carry = bits.Add64(r[1], 6461107452199829505, carry) + r[2], carry = bits.Add64(r[2], 6968279316240510977, carry) + r[3], _ = bits.Add64(r[3], 1345280370688173398, carry) + + } + } + if (u[0] == 1) && (u[3]|u[2]|u[1]) == 0 { + z.Set(&r) + return z + } + if (v[0] == 1) && (v[3]|v[2]|v[1]) == 0 { + z.Set(&s) + return z + } + } + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_fuzz.go new file mode 100644 index 0000000000..a4c87eb250 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_fuzz.go @@ -0,0 +1,136 @@ +//go:build gofuzz +// +build gofuzz + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "bytes" + "encoding/binary" + "io" + "math/big" + "math/bits" +) + +const ( + fuzzInteresting = 1 + fuzzNormal = 0 + fuzzDiscard = -1 +) + +// Fuzz arithmetic operations fuzzer +func Fuzz(data []byte) int { + r := bytes.NewReader(data) + + var e1, e2 Element + e1.SetRawBytes(r) + e2.SetRawBytes(r) + + { + // mul assembly + + var c, _c Element + a, _a, b, _b := e1, e1, e2, e2 + c.Mul(&a, &b) + _mulGeneric(&_c, &_a, &_b) + + if !c.Equal(&_c) { + panic("mul asm != mul generic on Element") + } + } + + { + // inverse + inv := e1 + inv.Inverse(&inv) + + var bInv, b1, b2 big.Int + e1.ToBigIntRegular(&b1) + bInv.ModInverse(&b1, Modulus()) + inv.ToBigIntRegular(&b2) + + if b2.Cmp(&bInv) != 0 { + panic("inverse operation doesn't match big int result") + } + } + + { + // a + -a == 0 + a, b := e1, e1 + b.Neg(&b) + a.Add(&a, &b) + if !a.IsZero() { + panic("a + -a != 0") + } + } + + return fuzzNormal + +} + +// SetRawBytes reads up to Bytes (bytes needed to represent Element) from reader +// and interpret it as big endian uint64 +// used for fuzzing purposes only +func (z *Element) SetRawBytes(r io.Reader) { + + buf := make([]byte, 8) + + for i := 0; i < len(z); i++ { + if _, err := io.ReadFull(r, buf); err != nil { + goto eof + } + z[i] = binary.BigEndian.Uint64(buf[:]) + } +eof: + z[3] %= qElement[3] + + if z.BiggerModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], qElement[0], 0) + z[1], b = bits.Sub64(z[1], qElement[1], b) + z[2], b = bits.Sub64(z[2], qElement[2], b) + z[3], b = bits.Sub64(z[3], qElement[3], b) + } + + return +} + +func (z *Element) BiggerModulus() bool { + if z[3] > qElement[3] { + return true + } + if z[3] < qElement[3] { + return false + } + + if z[2] > qElement[2] { + return true + } + if z[2] < qElement[2] { + return false + } + + if z[1] > qElement[1] { + return true + } + if z[1] < qElement[1] { + return false + } + + return z[0] >= qElement[0] +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_adx_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_adx_amd64.s new file mode 100644 index 0000000000..382e72164c --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_adx_amd64.s @@ -0,0 +1,466 @@ +// +build amd64_adx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x0a11800000000001 +DATA q<>+8(SB)/8, $0x59aa76fed0000001 +DATA q<>+16(SB)/8, $0x60b44d1e5c37b001 +DATA q<>+24(SB)/8, $0x12ab655e9a2ca556 +GLOBL q<>(SB), (RODATA+NOPTR), $32 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x0a117fffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), NOSPLIT, $0-24 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + MOVQ x+8(FP), SI + + // x[0] -> DI + // x[1] -> R8 + // x[2] -> R9 + // x[3] -> R10 + MOVQ 0(SI), DI + MOVQ 8(SI), R8 + MOVQ 16(SI), R9 + MOVQ 24(SI), R10 + MOVQ y+16(FP), R11 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // clear the flags + XORQ AX, AX + MOVQ 0(R11), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ DI, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R8, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R9, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 8(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 16(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 24(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // reduce element(R14,R15,CX,BX) using temp registers (R13,SI,R12,R11) + REDUCE(R14,R15,CX,BX,R13,SI,R12,R11) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + RET + +TEXT ·fromMont(SB), NOSPLIT, $0-8 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + + // reduce element(R14,R15,CX,BX) using temp registers (SI,DI,R8,R9) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s new file mode 100644 index 0000000000..d33a519c3d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s @@ -0,0 +1,488 @@ +// +build !amd64_adx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x0a11800000000001 +DATA q<>+8(SB)/8, $0x59aa76fed0000001 +DATA q<>+16(SB)/8, $0x60b44d1e5c37b001 +DATA q<>+24(SB)/8, $0x12ab655e9a2ca556 +GLOBL q<>(SB), (RODATA+NOPTR), $32 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x0a117fffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), $24-24 + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 + MOVQ x+8(FP), SI + + // x[0] -> DI + // x[1] -> R8 + // x[2] -> R9 + // x[3] -> R10 + MOVQ 0(SI), DI + MOVQ 8(SI), R8 + MOVQ 16(SI), R9 + MOVQ 24(SI), R10 + MOVQ y+16(FP), R11 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // clear the flags + XORQ AX, AX + MOVQ 0(R11), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ DI, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R8, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R9, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 8(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 16(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // clear the flags + XORQ AX, AX + MOVQ 24(R11), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ DI, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R8, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R9, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ R10, AX, BP + ADOXQ AX, BX + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R12 + ADCXQ R14, AX + MOVQ R12, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // t[3] = C + A + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ BP, BX + + // reduce element(R14,R15,CX,BX) using temp registers (R13,SI,R12,R11) + REDUCE(R14,R15,CX,BX,R13,SI,R12,R11) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + RET + +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS + + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + MOVQ $0, AX + ADCXQ AX, BX + ADOXQ AX, BX + + // reduce element(R14,R15,CX,BX) using temp registers (SI,DI,R8,R9) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go new file mode 100644 index 0000000000..78022b3e6f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go @@ -0,0 +1,50 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func add(res, x, y *Element) + +//go:noescape +func sub(res, x, y *Element) + +//go:noescape +func neg(res, x *Element) + +//go:noescape +func double(res, x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +//go:noescape +func Butterfly(a, b *Element) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s new file mode 100644 index 0000000000..85a1c457fb --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s @@ -0,0 +1,340 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x0a11800000000001 +DATA q<>+8(SB)/8, $0x59aa76fed0000001 +DATA q<>+16(SB)/8, $0x60b44d1e5c37b001 +DATA q<>+24(SB)/8, $0x12ab655e9a2ca556 +GLOBL q<>(SB), (RODATA+NOPTR), $32 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x0a117fffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +// add(res, x, y *Element) +TEXT ·add(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ y+16(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + + // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + + MOVQ res+0(FP), R12 + MOVQ CX, 0(R12) + MOVQ BX, 8(R12) + MOVQ SI, 16(R12) + MOVQ DI, 24(R12) + RET + +// sub(res, x, y *Element) +TEXT ·sub(SB), NOSPLIT, $0-24 + XORQ DI, DI + MOVQ x+8(FP), SI + MOVQ 0(SI), AX + MOVQ 8(SI), DX + MOVQ 16(SI), CX + MOVQ 24(SI), BX + MOVQ y+16(FP), SI + SUBQ 0(SI), AX + SBBQ 8(SI), DX + SBBQ 16(SI), CX + SBBQ 24(SI), BX + MOVQ $0x0a11800000000001, R8 + MOVQ $0x59aa76fed0000001, R9 + MOVQ $0x60b44d1e5c37b001, R10 + MOVQ $0x12ab655e9a2ca556, R11 + CMOVQCC DI, R8 + CMOVQCC DI, R9 + CMOVQCC DI, R10 + CMOVQCC DI, R11 + ADDQ R8, AX + ADCQ R9, DX + ADCQ R10, CX + ADCQ R11, BX + MOVQ res+0(FP), R12 + MOVQ AX, 0(R12) + MOVQ DX, 8(R12) + MOVQ CX, 16(R12) + MOVQ BX, 24(R12) + RET + +// double(res, x *Element) +TEXT ·double(SB), NOSPLIT, $0-16 + MOVQ x+8(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ res+0(FP), R11 + MOVQ DX, 0(R11) + MOVQ CX, 8(R11) + MOVQ BX, 16(R11) + MOVQ SI, 24(R11) + RET + +// neg(res, x *Element) +TEXT ·neg(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DI + MOVQ x+8(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ DX, AX + ORQ CX, AX + ORQ BX, AX + ORQ SI, AX + TESTQ AX, AX + JEQ l1 + MOVQ $0x0a11800000000001, R8 + SUBQ DX, R8 + MOVQ R8, 0(DI) + MOVQ $0x59aa76fed0000001, R8 + SBBQ CX, R8 + MOVQ R8, 8(DI) + MOVQ $0x60b44d1e5c37b001, R8 + SBBQ BX, R8 + MOVQ R8, 16(DI) + MOVQ $0x12ab655e9a2ca556, R8 + SBBQ SI, R8 + MOVQ R8, 24(DI) + RET + +l1: + MOVQ AX, 0(DI) + MOVQ AX, 8(DI) + MOVQ AX, 16(DI) + MOVQ AX, 24(DI) + RET + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R15,DI,R8,R9) + REDUCE(DX,CX,BX,SI,R15,DI,R8,R9) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, R11 + MOVQ CX, R12 + MOVQ BX, R13 + MOVQ SI, R14 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), NOSPLIT, $0-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ CX, R8 + MOVQ BX, R9 + MOVQ SI, R10 + MOVQ DI, R11 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + SUBQ 0(DX), R8 + SBBQ 8(DX), R9 + SBBQ 16(DX), R10 + SBBQ 24(DX), R11 + MOVQ $0x0a11800000000001, R12 + MOVQ $0x59aa76fed0000001, R13 + MOVQ $0x60b44d1e5c37b001, R14 + MOVQ $0x12ab655e9a2ca556, R15 + CMOVQCC AX, R12 + CMOVQCC AX, R13 + CMOVQCC AX, R14 + CMOVQCC AX, R15 + ADDQ R12, R8 + ADCQ R13, R9 + ADCQ R14, R10 + ADCQ R15, R11 + MOVQ R8, 0(DX) + MOVQ R9, 8(DX) + MOVQ R10, 16(DX) + MOVQ R11, 24(DX) + + // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_noasm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_noasm.go new file mode 100644 index 0000000000..ec1fac18d6 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_noasm.go @@ -0,0 +1,78 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +// MulBy3 x *= 3 +func MulBy3(x *Element) { + mulByConstant(x, 3) +} + +// MulBy5 x *= 5 +func MulBy5(x *Element) { + mulByConstant(x, 5) +} + +// MulBy13 x *= 13 +func MulBy13(x *Element) { + mulByConstant(x, 13) +} + +// Butterfly sets +// a = a + b +// b = a - b +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func mul(z, x, y *Element) { + _mulGeneric(z, x, y) +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func add(z, x, y *Element) { + _addGeneric(z, x, y) +} + +func double(z, x *Element) { + _doubleGeneric(z, x) +} + +func sub(z, x, y *Element) { + _subGeneric(z, x, y) +} + +func neg(z, x *Element) { + _negGeneric(z, x) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/doc.go new file mode 100644 index 0000000000..497bd40a97 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/doc.go @@ -0,0 +1,18 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package mimc provides MiMC hash function using Miyaguchi–Preneel construction. +package mimc diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/fuzz.go new file mode 100644 index 0000000000..41b557cf3f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/fuzz.go @@ -0,0 +1,34 @@ +//go:build gofuzz +// +build gofuzz + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +const ( + fuzzInteresting = 1 + fuzzNormal = 0 + fuzzDiscard = -1 +) + +func Fuzz(data []byte) int { + var s []byte + h := NewMiMC(string(data)) + h.Write(data) + h.Sum(s) + return fuzzNormal +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/mimc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/mimc.go new file mode 100644 index 0000000000..00ead7f443 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc/mimc.go @@ -0,0 +1,170 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package mimc + +import ( + "hash" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "golang.org/x/crypto/sha3" +) + +const mimcNbRounds = 91 + +// BlockSize size that mimc consumes +const BlockSize = fr.Bytes + +// Params constants for the mimc hash function +type Params []fr.Element + +// NewParams creates new mimc object +func NewParams(seed string) Params { + + // set the constants + res := make(Params, mimcNbRounds) + + rnd := sha3.Sum256([]byte(seed)) + value := new(big.Int).SetBytes(rnd[:]) + + for i := 0; i < mimcNbRounds; i++ { + rnd = sha3.Sum256(value.Bytes()) + value.SetBytes(rnd[:]) + res[i].SetBigInt(value) + } + + return res +} + +// digest represents the partial evaluation of the checksum +// along with the params of the mimc function +type digest struct { + Params Params + h fr.Element + data []byte // data to hash +} + +// NewMiMC returns a MiMCImpl object, pure-go reference implementation +func NewMiMC(seed string) hash.Hash { + d := new(digest) + params := NewParams(seed) + //d.Reset() + d.Params = params + d.Reset() + return d +} + +// Reset resets the Hash to its initial state. +func (d *digest) Reset() { + d.data = nil + d.h = fr.Element{0, 0, 0, 0} +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (d *digest) Sum(b []byte) []byte { + buffer := d.checksum() + d.data = nil // flush the data already hashed + hash := buffer.Bytes() + b = append(b, hash[:]...) + return b +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (d *digest) Size() int { + return BlockSize +} + +// BlockSize returns the number of bytes Sum will return. +func (d *digest) BlockSize() int { + return BlockSize +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + d.data = append(d.data, p...) + return +} + +// Hash hash using Miyaguchi–Preneel: +// https://en.wikipedia.org/wiki/One-way_compression_function +// The XOR operation is replaced by field addition, data is in Montgomery form +func (d *digest) checksum() fr.Element { + + var buffer [BlockSize]byte + var x fr.Element + + // if data size is not multiple of BlockSizes we padd: + // .. || 0xaf8 -> .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + +// plain execution of a mimc run +// m: message +// k: encryption key +func (d *digest) encrypt(m fr.Element) { + + for i := 0; i < len(d.Params); i++ { + // m = (m+k+c)^**-1 + m.Add(&m, &d.h).Add(&m, &d.Params[i]).Inverse(&m) + } + m.Add(&m, &d.h) + d.h = m +} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fuzz.go new file mode 100644 index 0000000000..c30604a2e8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fuzz.go @@ -0,0 +1,76 @@ +//go:build gofuzz +// +build gofuzz + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "bytes" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc" + "math/big" +) + +const ( + fuzzInteresting = 1 + fuzzNormal = 0 + fuzzDiscard = -1 +) + +func Fuzz(data []byte) int { + // TODO separate in multiple FuzzXXX and update continuous fuzzer scripts + // else, we don't really benefits for fuzzer strategy. + fr.Fuzz(data) + fp.Fuzz(data) + mimc.Fuzz(data) + + // fuzz pairing + r := bytes.NewReader(data) + var e1, e2 fr.Element + e1.SetRawBytes(r) + e2.SetRawBytes(r) + + { + var r, r1, r2, r1r2, zero GT + var b1, b2, b1b2 big.Int + e1.ToBigIntRegular(&b1) + e2.ToBigIntRegular(&b2) + b1b2.Mul(&b1, &b2) + + var p1 G1Affine + var p2 G2Affine + + p1.ScalarMultiplication(&g1GenAff, &b1) + p2.ScalarMultiplication(&g2GenAff, &b2) + + r, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff}) + r1, _ = Pair([]G1Affine{p1}, []G2Affine{g2GenAff}) + r2, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{p2}) + + r1r2.Exp(&r, b1b2) + r1.Exp(&r1, b2) + r2.Exp(&r2, b1) + + if !(r1r2.Equal(&r1) && r1r2.Equal(&r2) && !r.Equal(&zero)) { + panic("pairing bilinearity check failed") + } + } + + return fuzzNormal +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go new file mode 100644 index 0000000000..ba35ac9148 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go @@ -0,0 +1,964 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "math" + "math/big" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" +) + +// G1Affine point in affine coordinates +type G1Affine struct { + X, Y fp.Element +} + +// G1Jac is a point with fp.Element coordinates +type G1Jac struct { + X, Y, Z fp.Element +} + +// g1JacExtended parameterized jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ**3=ZZZ**2) +type g1JacExtended struct { + X, Y, ZZ, ZZZ fp.Element +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G1Affine) Set(a *G1Affine) *G1Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// ScalarMultiplication computes and returns p = a*s +func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inneficient compared to Jacobian +// TODO implement affine addition formula +func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inneficient compared to Jacobian +// TODO implement affine addition formula +func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G1Affine) Equal(a *G1Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G1Affine) Neg(a *G1Affine) *G1Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescale a point in Jacobian coord in z=1 plane +func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { + + var a, b fp.Element + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +func (p *G1Affine) String() string { + var x, y fp.Element + x.Set(&p.X) + y.Set(&p.Y) + return "E([" + x.String() + "," + y.String() + "])," +} + +// IsInfinity checks if the point is infinity (in affine, it's encoded as (0,0)) +func (p *G1Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Affine) IsOnCurve() bool { + var point G1Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G1Affine) IsInSubGroup() bool { + var _p G1Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G1Jac) Set(a *G1Jac) *G1Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G1Jac) Equal(a *G1Jac) bool { + + if p.Z.IsZero() && a.Z.IsZero() { + return true + } + _p := G1Affine{} + _p.FromJacobian(p) + + _a := G1Affine{} + _a.FromJacobian(a) + + return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) +} + +// Neg computes -G +func (p *G1Jac) Neg(a *G1Jac) *G1Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign substracts two points on the curve +func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fp.Element + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) Double(q *G1Jac) *G1Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) DoubleAssign() *G1Jac { + + var XX, YY, YYYY, ZZ, S, M, T fp.Element + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a*s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(a, s) +} + +func (p *G1Jac) String() string { + if p.Z.IsZero() { + return "O" + } + _p := G1Affine{} + _p.FromJacobian(p) + return "E([" + _p.X.String() + "," + _p.Y.String() + "])," +} + +// FromAffine sets p = Q, p in Jacboian, Q in affine +func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { + if Q.X.IsZero() && Q.Y.IsZero() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Jac) IsOnCurve() bool { + var left, right, tmp fp.Element + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// IsInSubGroup returns true if p is on the r-torsion, false otherwise. +// Z[r,0]+Z[-lambdaG1Affine, 1] is the kernel +// of (u,v)->u+lambdaG1Affinev mod r. Expressing r, lambdaG1Affine as +// polynomials in x, a short vector of this Zmodule is +// 1, x**2. So we check that p+x**2*phi(p) +// is the infinity. +func (p *G1Jac) IsInSubGroup() bool { + + var res G1Jac + res.phi(p). + ScalarMultiplication(&res, &xGen). + ScalarMultiplication(&res, &xGen). + AddAssign(p) + + return res.IsOnCurve() && res.Z.IsZero() + +} + +// mulWindowed 2-bits windowed exponentiation +func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { + + var res G1Jac + var ops [3]G1Jac + + res.Set(&g1Infinity) + ops[0].Set(a) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// phi assigns p to phi(a) where phi: (x,y)->(ux,y), and returns p +func (p *G1Jac) phi(a *G1Jac) *G1Jac { + p.Set(a) + p.X.Mul(&p.X, &thirdRootOneG1) + return p +} + +// mulGLV performs scalar multiplication using GLV +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { + + var table [15]G1Jac + var res G1Jac + var k1, k2 fr.Element + + res.Set(&g1Infinity) + + // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies +-a, phi(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 bits long max + k1.SetBigInt(&k[0]).FromMont() + k2.SetBigInt(&k[1]).FromMont() + + // loop starts from len(k1)/2 due to the bounds + for i := int(math.Ceil(fr.Limbs/2. - 1)); i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in E(Fp) to E(Fp)[r] +func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { + // cf https://eprint.iacr.org/2019/403.pdf, 5 + var res G1Jac + res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + p.Set(&res) + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g1JacExtended) setInfinity() *g1JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p +} + +// fromJacExtended sets Q in affine coords +func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { + if Q.ZZ.IsZero() { + p.X = fp.Element{} + p.Y = fp.Element{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coords +func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { + if Q.ZZ.IsZero() { + p.Set(&g1Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in jacobian coords, but don't check for infinity +func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in ZZ coords +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, X1ZZ2, X2ZZ1, Y1ZZZ2, Y2ZZZ1 fp.Element + + // p2: q, p1: p + X2ZZ1.Mul(&q.X, &p.ZZ) + X1ZZ2.Mul(&p.X, &q.ZZ) + A.Sub(&X2ZZ1, &X1ZZ2) + Y2ZZZ1.Mul(&q.Y, &p.ZZZ) + Y1ZZZ2.Mul(&p.Y, &q.ZZZ) + B.Sub(&Y2ZZZ1, &Y1ZZZ2) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var U1, U2, S1, S2, P, R, PP, PPP, Q, V fp.Element + U1.Mul(&p.X, &q.ZZ) + U2.Mul(&q.X, &p.ZZ) + S1.Mul(&p.Y, &q.ZZZ) + S2.Mul(&q.Y, &p.ZZZ) + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in ZZ coords +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { + var U, V, W, S, XX, M fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in ZZ coords +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates +// performing a single field inversion (Montgomery batch inversion trick) +// result must be allocated with len(result) == len(points) +func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { + zeroes := make([]bool, len(points)) + accumulator := fp.One() + + // batch invert all points[].Z coordinates with Montgomery batch inversion trick + // (stores points[].Z^-1 in result[i].X to avoid allocating a slice of fr.Elements) + for i := 0; i < len(points); i++ { + if points[i].Z.IsZero() { + zeroes[i] = true + continue + } + result[i].X = accumulator + accumulator.Mul(&accumulator, &points[i].Z) + } + + var accInverse fp.Element + accInverse.Inverse(&accumulator) + + for i := len(points) - 1; i >= 0; i-- { + if zeroes[i] { + // do nothing, X and Y are zeroes in affine. + continue + } + result[i].X.Mul(&result[i].X, &accInverse) + accInverse.Mul(&accInverse, &points[i].Z) + } + + // batch convert to affine. + parallel.Execute(len(points), func(start, end int) { + for i := start; i < end; i++ { + if zeroes[i] { + // do nothing, X and Y are zeroes in affine. + continue + } + var a, b fp.Element + a = result[i].X + b.Square(&a) + result[i].X.Mul(&points[i].X, &b) + result[i].Y.Mul(&points[i].Y, &b). + Mul(&result[i].Y, &a) + } + }) + +} + +// BatchScalarMultiplicationG1 multiplies the same base (generator) by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { + + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c < 18; c++ { + cost := uint64(1 << (c - 1)) + nbChunks := uint64(fr.Limbs * 64 / c) + if (fr.Limbs*64)%c != 0 { + nbChunks++ + } + cost += nbPoints * ((fr.Limbs * 64) + nbChunks) + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(fr.Limbs * 64 / c) + if (fr.Limbs*64)%c != 0 { + nbChunks++ + } + mask := uint64((1 << c) - 1) // low c bits are 1 + msbWindow := uint64(1 << (c - 1)) + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G1Jac, (1 << (c - 1))) + baseTable[0].Set(&g1Infinity) + baseTable[0].AddMixed(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + + pScalars, _ := partitionScalars(scalars, c, false, runtime.NumCPU()) + + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := 0; chunk < nbChunks; chunk++ { + jc := uint64(uint64(chunk) * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = (64%c) != 0 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d + } + // convert our base exp table into affine to use AddMixed + baseTableAff := make([]G1Affine, (1 << (c - 1))) + BatchJacobianToAffineG1(baseTable, baseTableAff) + toReturn := make([]G1Jac, len(scalars)) + + // for each digit, take value in the base table, double it c time, voila. + parallel.Execute(len(pScalars), func(start, end int) { + var p G1Jac + for i := start; i < end; i++ { + p.Set(&g1Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + s := selectors[chunk] + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + + bits := (pScalars[i][s.index] & s.mask) >> s.shift + if s.multiWordSelect { + bits += (pScalars[i][s.index+1] & s.maskHigh) << s.shiftHigh + } + + if bits == 0 { + continue + } + + // if msbWindow bit is set, we need to substract + if bits&msbWindow == 0 { + // add + p.AddMixed(&baseTableAff[bits-1]) + } else { + // sub + t := baseTableAff[bits & ^msbWindow] + t.Neg(&t) + p.AddMixed(&t) + } + } + + // set our result point + toReturn[i] = p + + } + }) + toReturnAff := make([]G1Affine, len(scalars)) + BatchJacobianToAffineG1(toReturn, toReturnAff) + return toReturnAff +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go new file mode 100644 index 0000000000..fa48409727 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go @@ -0,0 +1,978 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "math" + "math/big" + "runtime" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" +) + +// G2Affine point in affine coordinates +type G2Affine struct { + X, Y fptower.E2 +} + +// G2Jac is a point with fptower.E2 coordinates +type G2Jac struct { + X, Y, Z fptower.E2 +} + +// g2JacExtended parameterized jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ**3=ZZZ**2) +type g2JacExtended struct { + X, Y, ZZ, ZZZ fptower.E2 +} + +// g2Proj point in projective coordinates +type g2Proj struct { + x, y, z fptower.E2 +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G2Affine) Set(a *G2Affine) *G2Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// ScalarMultiplication computes and returns p = a*s +func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inneficient compared to Jacobian +// TODO implement affine addition formula +func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inneficient compared to Jacobian +// TODO implement affine addition formula +func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G2Affine) Equal(a *G2Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G2Affine) Neg(a *G2Affine) *G2Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescale a point in Jacobian coord in z=1 plane +func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { + + var a, b fptower.E2 + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +func (p *G2Affine) String() string { + var x, y fptower.E2 + x.Set(&p.X) + y.Set(&p.Y) + return "E([" + x.String() + "," + y.String() + "])," +} + +// IsInfinity checks if the point is infinity (in affine, it's encoded as (0,0)) +func (p *G2Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Affine) IsOnCurve() bool { + var point G2Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G2Affine) IsInSubGroup() bool { + var _p G2Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G2Jac) Set(a *G2Jac) *G2Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G2Jac) Equal(a *G2Jac) bool { + + if p.Z.IsZero() && a.Z.IsZero() { + return true + } + _p := G2Affine{} + _p.FromJacobian(p) + + _a := G2Affine{} + _a.FromJacobian(a) + + return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) +} + +// Neg computes -G +func (p *G2Jac) Neg(a *G2Jac) *G2Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign substracts two points on the curve +func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fptower.E2 + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) Double(q *G2Jac) *G2Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) DoubleAssign() *G2Jac { + + var XX, YY, YYYY, ZZ, S, M, T fptower.E2 + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a*s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(a, s) +} + +func (p *G2Jac) String() string { + if p.Z.IsZero() { + return "O" + } + _p := G2Affine{} + _p.FromJacobian(p) + return "E([" + _p.X.String() + "," + _p.Y.String() + "])," +} + +// FromAffine sets p = Q, p in Jacboian, Q in affine +func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { + if Q.X.IsZero() && Q.Y.IsZero() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Jac) IsOnCurve() bool { + var left, right, tmp fptower.E2 + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bTwistCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// https://eprint.iacr.org/2021/1130.pdf, sec.4 +// psi(p) = u*P +func (p *G2Jac) IsInSubGroup() bool { + var res, tmp G2Jac + tmp.psi(p) + res.ScalarMultiplication(p, &xGen). + SubAssign(&tmp) + + return res.IsOnCurve() && res.Z.IsZero() +} + +// mulWindowed 2-bits windowed exponentiation +func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { + + var res G2Jac + var ops [3]G2Jac + + res.Set(&g2Infinity) + ops[0].Set(a) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// psi(p) = u o frob o u**-1 where u:E'->E iso from the twist to E +func (p *G2Jac) psi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) + p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) + p.Z.Conjugate(&p.Z) + return p +} + +// phi assigns p to phi(a) where phi: (x,y)->(ux,y), and returns p +func (p *G2Jac) phi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.MulByElement(&p.X, &thirdRootOneG2) + return p +} + +// mulGLV performs scalar multiplication using GLV +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { + + var table [15]G2Jac + var res G2Jac + var k1, k2 fr.Element + + res.Set(&g2Infinity) + + // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies +-a, phi(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 bits long max + k1.SetBigInt(&k[0]).FromMont() + k2.SetBigInt(&k[1]).FromMont() + + // loop starts from len(k1)/2 due to the bounds + for i := int(math.Ceil(fr.Limbs/2. - 1)); i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { + // https://eprint.iacr.org/2017/419.pdf, 4.1 + var xg, xxg, res, t G2Jac + xg.ScalarMultiplication(a, &xGen) + xxg.ScalarMultiplication(&xg, &xGen) + + res.Set(&xxg). + SubAssign(&xg). + SubAssign(a) + + t.Set(&xg). + SubAssign(a). + psi(&t) + + res.AddAssign(&t) + + t.Double(a) + t.X.MulByElement(&t.X, &thirdRootOneG1) + + res.SubAssign(&t) + + p.Set(&res) + + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g2JacExtended) setInfinity() *g2JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p +} + +// fromJacExtended sets Q in affine coords +func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { + if Q.ZZ.IsZero() { + p.X = fptower.E2{} + p.Y = fptower.E2{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coords +func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { + if Q.ZZ.IsZero() { + p.Set(&g2Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in jacobian coords, but don't check for infinity +func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in ZZ coords +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, X1ZZ2, X2ZZ1, Y1ZZZ2, Y2ZZZ1 fptower.E2 + + // p2: q, p1: p + X2ZZ1.Mul(&q.X, &p.ZZ) + X1ZZ2.Mul(&p.X, &q.ZZ) + A.Sub(&X2ZZ1, &X1ZZ2) + Y2ZZZ1.Mul(&q.Y, &p.ZZZ) + Y1ZZZ2.Mul(&p.Y, &q.ZZZ) + B.Sub(&Y2ZZZ1, &Y1ZZZ2) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var U1, U2, S1, S2, P, R, PP, PPP, Q, V fptower.E2 + U1.Mul(&p.X, &q.ZZ) + U2.Mul(&q.X, &p.ZZ) + S1.Mul(&p.Y, &q.ZZZ) + S2.Mul(&q.Y, &p.ZZZ) + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in ZZ coords +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { + var U, V, W, S, XX, M fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.X.IsZero() && a.Y.IsZero() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in ZZ coords +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// ------------------------------------------------------------------------------------------------- +// Homogenous projective + +// Set sets p to the provided point +func (p *g2Proj) Set(a *g2Proj) *g2Proj { + p.x, p.y, p.z = a.x, a.y, a.z + return p +} + +// Neg computes -G +func (p *g2Proj) Neg(a *g2Proj) *g2Proj { + *p = *a + p.y.Neg(&a.y) + return p +} + +// FromJacobian converts a point from Jacobian to projective coordinates +func (p *g2Proj) FromJacobian(Q *G2Jac) *g2Proj { + var buf fptower.E2 + buf.Square(&Q.Z) + + p.x.Mul(&Q.X, &Q.Z) + p.y.Set(&Q.Y) + p.z.Mul(&Q.Z, &buf) + + return p +} + +// FromAffine sets p = Q, p in homogenous projective, Q in affine +func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { + if Q.X.IsZero() && Q.Y.IsZero() { + p.z.SetZero() + p.x.SetOne() + p.y.SetOne() + return p + } + p.z.SetOne() + p.x.Set(&Q.X) + p.y.Set(&Q.Y) + return p +} + +// BatchScalarMultiplicationG2 multiplies the same base (generator) by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { + + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c < 18; c++ { + cost := uint64(1 << (c - 1)) + nbChunks := uint64(fr.Limbs * 64 / c) + if (fr.Limbs*64)%c != 0 { + nbChunks++ + } + cost += nbPoints * ((fr.Limbs * 64) + nbChunks) + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(fr.Limbs * 64 / c) + if (fr.Limbs*64)%c != 0 { + nbChunks++ + } + mask := uint64((1 << c) - 1) // low c bits are 1 + msbWindow := uint64(1 << (c - 1)) + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G2Jac, (1 << (c - 1))) + baseTable[0].Set(&g2Infinity) + baseTable[0].AddMixed(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + + pScalars, _ := partitionScalars(scalars, c, false, runtime.NumCPU()) + + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := 0; chunk < nbChunks; chunk++ { + jc := uint64(uint64(chunk) * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = (64%c) != 0 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d + } + toReturn := make([]G2Affine, len(scalars)) + + // for each digit, take value in the base table, double it c time, voila. + parallel.Execute(len(pScalars), func(start, end int) { + var p G2Jac + for i := start; i < end; i++ { + p.Set(&g2Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + s := selectors[chunk] + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + + bits := (pScalars[i][s.index] & s.mask) >> s.shift + if s.multiWordSelect { + bits += (pScalars[i][s.index+1] & s.maskHigh) << s.shiftHigh + } + + if bits == 0 { + continue + } + + // if msbWindow bit is set, we need to substract + if bits&msbWindow == 0 { + // add + p.AddAssign(&baseTable[bits-1]) + } else { + // sub + t := baseTable[bits & ^msbWindow] + t.Neg(&t) + p.AddAssign(&t) + } + } + + // set our result point + toReturn[i].FromJacobian(&p) + + } + }) + return toReturn +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_curve.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_curve.go new file mode 100644 index 0000000000..ee8f42556b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_curve.go @@ -0,0 +1,276 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bls12377 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +// hashToFp hashes msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { + + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + L := 64 + + lenInBytes := count * L + pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + res := make([]fp.Element, count) + for i := 0; i < count; i++ { + res[i].SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + } + return res, nil +} + +// returns false if u>-u when seen as a bigInt +func sign0(u fp.Element) bool { + var a, b big.Int + u.ToBigIntRegular(&a) + u.Neg(&u) + u.ToBigIntRegular(&b) + return a.Cmp(&b) <= 0 +} + +// ---------------------------------------------------------------------------------------- +// G1Affine + +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1 +// Shallue and van de Woestijne method, works for any elliptic curve in Weierstrass curve +func svdwMapG1(u fp.Element) G1Affine { + + var res G1Affine + + // constants + // sage script to find z: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-E.1 + var z, c1, c2, c3, c4 fp.Element + z.SetOne() + c1.SetString("2") + c2.SetString("129332213006484547005326366847446766768196756377457330269942131333360234174170411387484444069786680062220160729088") + c3.SetString("97648839010665214827241242728596775338087731732850880761532715038339062821120154619091300503722809961039397351015") + c4.SetString("172442950675312729340435155796595689024262341836609773693256175111146978898893881849979258759715573416293547638782") + + var tv1, tv2, tv3, tv4, one, x1, gx1, x2, gx2, x3, x, gx, y fp.Element + one.SetOne() + tv1.Square(&u).Mul(&tv1, &c1) + tv2.Add(&one, &tv1) + tv1.Sub(&one, &tv1) + tv3.Mul(&tv2, &tv1).Inverse(&tv3) + tv4.Mul(&u, &tv1) + tv4.Mul(&tv4, &tv3) + tv4.Mul(&tv4, &c3) + x1.Sub(&c2, &tv4) + gx1.Square(&x1) + // 12. gx1 = gx1 + A + gx1.Mul(&gx1, &x1) + gx1.Add(&gx1, &bCurveCoeff) + e1 := gx1.Legendre() + x2.Add(&c2, &tv4) + gx2.Square(&x2) + // 18. gx2 = gx2 + A + gx2.Mul(&gx2, &x2) + gx2.Add(&gx2, &bCurveCoeff) + e2 := gx2.Legendre() - e1 // 2 if is_square(gx2) AND NOT e1 + x3.Square(&tv2) + x3.Mul(&x3, &tv3) + x3.Square(&x3) + x3.Mul(&x3, &c4) + x3.Add(&x3, &z) + if e1 == 1 { + x.Set(&x1) + } else { + x.Set(&x3) + } + if e2 == 2 { + x.Set(&x2) + } + gx.Square(&x) + // gx = gx + A + gx.Mul(&gx, &x) + gx.Add(&gx, &bCurveCoeff) + y.Sqrt(&gx) + e3 := sign0(u) && sign0(y) + if !e3 { + y.Neg(&y) + } + res.X.Set(&x) + res.Y.Set(&y) + + return res +} + +// MapToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.1 +func MapToCurveG1Svdw(t fp.Element) G1Affine { + res := svdwMapG1(t) + res.ClearCofactor(&res) + return res +} + +// EncodeToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.2 +func EncodeToCurveG1Svdw(msg, dst []byte) (G1Affine, error) { + var res G1Affine + t, err := hashToFp(msg, dst, 1) + if err != nil { + return res, err + } + res = MapToCurveG1Svdw(t[0]) + return res, nil +} + +// HashToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3 +func HashToCurveG1Svdw(msg, dst []byte) (G1Affine, error) { + var res G1Affine + u, err := hashToFp(msg, dst, 2) + if err != nil { + return res, err + } + Q0 := MapToCurveG1Svdw(u[0]) + Q1 := MapToCurveG1Svdw(u[1]) + var _Q0, _Q1, _res G1Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1) + _res.Set(&_Q1).AddAssign(&_Q0) + res.FromJacobian(&_res) + return res, nil +} + +// ---------------------------------------------------------------------------------------- +// G2Affine + +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1 +// Shallue and van de Woestijne method, works for any elliptic curve in Weierstrass curve +func svdwMapG2(u fptower.E2) G2Affine { + + var res G2Affine + + // constants + // sage script to find z: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-E.1 + var z, c1, c2, c3, c4 fptower.E2 + z.A0.SetString("258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176") + z.A1.SetString("258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176") + c1.A0.SetString("14") + c1.A1.SetString("155198655607781456406391640216936120121836107652948796323930557600032281009004493664981332883744016074664192874908") + c2.A0.SetString("129332213006484547005326366847446766768196756377457330269942131333360234174170411387484444069786680062220160729089") + c2.A1.SetString("129332213006484547005326366847446766768196756377457330269942131333360234174170411387484444069786680062220160729089") + c3.A0.SetString("136095077907295642446400609387283897242604839345760820213771221369353216046335543369711291750177599683819073207865") + c3.A1.SetString("219542929730243627071993942291259566263609334675640614684215562523644237982906136121780647979889503975135681203128") + c4.A0.SetString("182023114601718992081570442229739893970054694160865872231770407061766255504387986397200328690810883050532078063163") + c4.A1.SetString("13412229496968767837589401006401886924109293253958537953919924730866987247691746366109497903533433487933942594129") + + var tv1, tv2, tv3, tv4, one, x1, gx1, x2, gx2, x3, x, gx, y fptower.E2 + one.SetOne() + tv1.Square(&u).Mul(&tv1, &c1) + tv2.Add(&one, &tv1) + tv1.Sub(&one, &tv1) + tv3.Mul(&tv2, &tv1).Inverse(&tv3) + tv4.Mul(&u, &tv1) + tv4.Mul(&tv4, &tv3) + tv4.Mul(&tv4, &c3) + x1.Sub(&c2, &tv4) + gx1.Square(&x1) + // 12. gx1 = gx1 + A + gx1.Mul(&gx1, &x1) + gx1.Add(&gx1, &bTwistCurveCoeff) + e1 := gx1.Legendre() + x2.Add(&c2, &tv4) + gx2.Square(&x2) + // 18. gx2 = gx2 + A + gx2.Mul(&gx2, &x2) + gx2.Add(&gx2, &bTwistCurveCoeff) + e2 := gx2.Legendre() - e1 // 2 if is_square(gx2) AND NOT e1 + x3.Square(&tv2) + x3.Mul(&x3, &tv3) + x3.Square(&x3) + x3.Mul(&x3, &c4) + x3.Add(&x3, &z) + if e1 == 1 { + x.Set(&x1) + } else { + x.Set(&x3) + } + if e2 == 2 { + x.Set(&x2) + } + gx.Square(&x) + // gx = gx + A + gx.Mul(&gx, &x) + gx.Add(&gx, &bTwistCurveCoeff) + y.Sqrt(&gx) + e3 := sign0(u.A0) && sign0(y.A0) + if !e3 { + y.Neg(&y) + } + res.X.Set(&x) + res.Y.Set(&y) + + return res +} + +// MapToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.1 +func MapToCurveG2Svdw(t fptower.E2) G2Affine { + res := svdwMapG2(t) + res.ClearCofactor(&res) + return res +} + +// EncodeToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.2 +func EncodeToCurveG2Svdw(msg, dst []byte) (G2Affine, error) { + var res G2Affine + _t, err := hashToFp(msg, dst, 2) + if err != nil { + return res, err + } + var t fptower.E2 + t.A0.Set(&_t[0]) + t.A1.Set(&_t[1]) + res = MapToCurveG2Svdw(t) + return res, nil +} + +// HashToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3 +func HashToCurveG2Svdw(msg, dst []byte) (G2Affine, error) { + var res G2Affine + u, err := hashToFp(msg, dst, 4) + if err != nil { + return res, err + } + var u0, u1 fptower.E2 + u0.A0.Set(&u[0]) + u0.A1.Set(&u[1]) + u1.A0.Set(&u[2]) + u1.A1.Set(&u[3]) + Q0 := MapToCurveG2Svdw(u0) + Q1 := MapToCurveG2Svdw(u1) + var _Q0, _Q1, _res G2Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1) + _res.Set(&_Q1).AddAssign(&_Q0) + res.FromJacobian(&_res) + return res, nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go new file mode 100644 index 0000000000..0ec192019d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go @@ -0,0 +1,28 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import "golang.org/x/sys/cpu" + +// supportAdx will be set only on amd64 that has MULX and ADDX instructions +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx // used in asm +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go new file mode 100644 index 0000000000..6a09c11c49 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go @@ -0,0 +1,25 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go new file mode 100644 index 0000000000..cbc2606db8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go @@ -0,0 +1,561 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "encoding/binary" + "errors" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "math/big" +) + +// E12 is a degree two finite field extension of fp6 +type E12 struct { + C0, C1 E6 +} + +// Equal returns true if z equals x, fasle otherwise +func (z *E12) Equal(x *E12) bool { + return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) +} + +// String puts E12 in string form +func (z *E12) String() string { + return (z.C0.String() + "+(" + z.C1.String() + ")*w") +} + +// SetString sets a E12 from string +func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { + z.C0.SetString(s0, s1, s2, s3, s4, s5) + z.C1.SetString(s6, s7, s8, s9, s10, s11) + return z +} + +// Set copies x into z and returns z +func (z *E12) Set(x *E12) *E12 { + z.C0 = x.C0 + z.C1 = x.C1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E12) SetOne() *E12 { + *z = E12{} + z.C0.B0.A0.SetOne() + return z +} + +// ToMont converts to Mont form +func (z *E12) ToMont() *E12 { + z.C0.ToMont() + z.C1.ToMont() + return z +} + +// FromMont converts from Mont form +func (z *E12) FromMont() *E12 { + z.C0.FromMont() + z.C1.FromMont() + return z +} + +// Add set z=x+y in E12 and return z +func (z *E12) Add(x, y *E12) *E12 { + z.C0.Add(&x.C0, &y.C0) + z.C1.Add(&x.C1, &y.C1) + return z +} + +// Sub sets z to x sub y and return z +func (z *E12) Sub(x, y *E12) *E12 { + z.C0.Sub(&x.C0, &y.C0) + z.C1.Sub(&x.C1, &y.C1) + return z +} + +// Double sets z=2*x and returns z +func (z *E12) Double(x *E12) *E12 { + z.C0.Double(&x.C0) + z.C1.Double(&x.C1) + return z +} + +// SetRandom used only in tests +func (z *E12) SetRandom() (*E12, error) { + if _, err := z.C0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.C1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// Mul set z=x*y in E12 and return z +func (z *E12) Mul(x, y *E12) *E12 { + var a, b, c E6 + a.Add(&x.C0, &x.C1) + b.Add(&y.C0, &y.C1) + a.Mul(&a, &b) + b.Mul(&x.C0, &y.C0) + c.Mul(&x.C1, &y.C1) + z.C1.Sub(&a, &b).Sub(&z.C1, &c) + z.C0.MulByNonResidue(&c).Add(&z.C0, &b) + return z +} + +// Square set z=x*x in E12 and return z +func (z *E12) Square(x *E12) *E12 { + + //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf + var c0, c2, c3 E6 + c0.Sub(&x.C0, &x.C1) + c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3) + c2.Mul(&x.C0, &x.C1) + c0.Mul(&c0, &c3).Add(&c0, &c2) + z.C1.Double(&c2) + c2.MulByNonResidue(&c2) + z.C0.Add(&c0, &c2) + + return z +} + +// Karabina's compressed cyclotomic square +// https://eprint.iacr.org/2010/542.pdf +// Th. 3.2 with minor modifications to fit our tower +func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { + + var t [7]E2 + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = g5^2 + t[1].Square(&x.C1.B2) + // t5 = g1 + g5 + t[5].Add(&x.C0.B1, &x.C1.B2) + // t2 = (g1 + g5)^2 + t[2].Square(&t[5]) + + // t3 = g1^2 + g5^2 + t[3].Add(&t[0], &t[1]) + // t5 = 2 * g1 * g5 + t[5].Sub(&t[2], &t[3]) + + // t6 = g3 + g2 + t[6].Add(&x.C1.B0, &x.C0.B2) + // t3 = (g3 + g2)^2 + t[3].Square(&t[6]) + // t2 = g3^2 + t[2].Square(&x.C1.B0) + + // t6 = 2 * nr * g1 * g5 + t[6].MulByNonResidue(&t[5]) + // t5 = 4 * nr * g1 * g5 + 2 * g3 + t[5].Add(&t[6], &x.C1.B0). + Double(&t[5]) + // z3 = 6 * nr * g1 * g5 + 2 * g3 + z.C1.B0.Add(&t[5], &t[6]) + + // t4 = nr * g5^2 + t[4].MulByNonResidue(&t[1]) + // t5 = nr * g5^2 + g1^2 + t[5].Add(&t[0], &t[4]) + // t6 = nr * g5^2 + g1^2 - g2 + t[6].Sub(&t[5], &x.C0.B2) + + // t1 = g2^2 + t[1].Square(&x.C0.B2) + + // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 + t[6].Double(&t[6]) + // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 + z.C0.B2.Add(&t[6], &t[5]) + + // t4 = nr * g2^2 + t[4].MulByNonResidue(&t[1]) + // t5 = g3^2 + nr * g2^2 + t[5].Add(&t[2], &t[4]) + // t6 = g3^2 + nr * g2^2 - g1 + t[6].Sub(&t[5], &x.C0.B1) + // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 + t[6].Double(&t[6]) + // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 + z.C0.B1.Add(&t[6], &t[5]) + + // t0 = g2^2 + g3^2 + t[0].Add(&t[2], &t[1]) + // t5 = 2 * g3 * g2 + t[5].Sub(&t[3], &t[0]) + // t6 = 2 * g3 * g2 + g5 + t[6].Add(&t[5], &x.C1.B2) + // t6 = 4 * g3 * g2 + 2 * g5 + t[6].Double(&t[6]) + // z5 = 6 * g3 * g2 + 2 * g5 + z.C1.B2.Add(&t[5], &t[6]) + + return z +} + +// Decompress Karabina's cyclotomic square result +func (z *E12) Decompress(x *E12) *E12 { + + var t [3]E2 + var one E2 + one.SetOne() + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t[1].Sub(&t[0], &x.C0.B2). + Double(&t[1]). + Add(&t[1], &t[0]) + // t0 = E * g5^2 + t1 + t[2].Square(&x.C1.B2) + t[0].MulByNonResidue(&t[2]). + Add(&t[0], &t[1]) + // t1 = 1/(4 * g3) + t[1].Double(&x.C1.B0). + Double(&t[1]). + Inverse(&t[1]) // costly + // z4 = g4 + z.C1.B1.Mul(&t[0], &t[1]) + + // t1 = g2 * g1 + t[1].Mul(&x.C0.B2, &x.C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t[2].Square(&z.C1.B1). + Sub(&t[2], &t[1]). + Double(&t[2]). + Sub(&t[2], &t[1]) + // t1 = g3 * g5 + t[1].Mul(&x.C1.B0, &x.C1.B2) + // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t[2].Add(&t[2], &t[1]) + z.C0.B0.MulByNonResidue(&t[2]). + Add(&z.C0.B0, &one) + + z.C0.B1.Set(&x.C0.B1) + z.C0.B2.Set(&x.C0.B2) + z.C1.B0.Set(&x.C1.B0) + z.C1.B2.Set(&x.C1.B2) + + return z +} + +// BatchDecompress multiple Karabina's cyclotomic square results +func BatchDecompress(x []E12) []E12 { + + n := len(x) + if n == 0 { + return x + } + + t0 := make([]E2, n) + t1 := make([]E2, n) + t2 := make([]E2, n) + + var one E2 + one.SetOne() + + for i := 0; i < n; i++ { + // t0 = g1^2 + t0[i].Square(&x[i].C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t1[i].Sub(&t0[i], &x[i].C0.B2). + Double(&t1[i]). + Add(&t1[i], &t0[i]) + // t0 = E * g5^2 + t1 + t2[i].Square(&x[i].C1.B2) + t0[i].MulByNonResidue(&t2[i]). + Add(&t0[i], &t1[i]) + // t1 = 4 * g3 + t1[i].Double(&x[i].C1.B0). + Double(&t1[i]) + } + + t1 = BatchInvert(t1) // costs 1 inverse + + for i := 0; i < n; i++ { + // z4 = g4 + x[i].C1.B1.Mul(&t0[i], &t1[i]) + + // t1 = g2 * g1 + t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t2[i].Square(&x[i].C1.B1) + t2[i].Sub(&t2[i], &t1[i]) + t2[i].Double(&t2[i]) + t2[i].Sub(&t2[i], &t1[i]) + + // t1 = g3 * g5 + t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) + // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t2[i].Add(&t2[i], &t1[i]) + x[i].C0.B0.MulByNonResidue(&t2[i]). + Add(&x[i].C0.B0, &one) + } + + return x +} + +// Granger-Scott's cyclotomic square +// https://eprint.iacr.org/2009/565.pdf, 3.2 +func (z *E12) CyclotomicSquare(x *E12) *E12 { + + // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6 + // cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0, + // 3*x2^2*u + 3*x3^2 - 2*x1, + // 3*x5^2*u + 3*x1^2 - 2*x2, + // 6*x1*x5*u + 2*x3, + // 6*x0*x4 + 2*x4, + // 6*x2*x3 + 2*x5) + + var t [9]E2 + + t[0].Square(&x.C1.B1) + t[1].Square(&x.C0.B0) + t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0 + t[2].Square(&x.C0.B2) + t[3].Square(&x.C1.B0) + t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3 + t[4].Square(&x.C1.B2) + t[5].Square(&x.C0.B1) + t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u + + t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2 + t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2 + t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2 + + z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0]) + z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2]) + z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4]) + + z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8]) + z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6]) + z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7]) + + return z +} + +// Inverse set z to the inverse of x in E12 and return z +func (z *E12) Inverse(x *E12) *E12 { + // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf + + var t0, t1, tmp E6 + t0.Square(&x.C0) + t1.Square(&x.C1) + tmp.MulByNonResidue(&t1) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.C0.Mul(&x.C0, &t1) + z.C1.Mul(&x.C1, &t1).Neg(&z.C1) + + return z +} + +// Exp sets z=x**e and returns it +func (z *E12) Exp(x *E12, e big.Int) *E12 { + var res E12 + res.SetOne() + b := e.Bytes() + for i := range b { + w := b[i] + mask := byte(0x80) + for j := 7; j >= 0; j-- { + res.Square(&res) + if (w&mask)>>j != 0 { + res.Mul(&res, x) + } + mask = mask >> 1 + } + } + z.Set(&res) + return z +} + +// InverseUnitary inverse a unitary element +func (z *E12) InverseUnitary(x *E12) *E12 { + return z.Conjugate(x) +} + +// Conjugate set z to x conjugated and return z +func (z *E12) Conjugate(x *E12) *E12 { + *z = *x + z.C1.Neg(&z.C1) + return z +} + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = 48 * 12 + +// Marshal converts z to a byte slice +func (z *E12) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an allias to SetBytes() +func (z *E12) Unmarshal(buf []byte) error { + return z.SetBytes(buf) +} + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) Bytes() (r [SizeOfGT]byte) { + _z := *z + _z.FromMont() + binary.BigEndian.PutUint64(r[568:576], _z.C0.B0.A0[0]) + binary.BigEndian.PutUint64(r[560:568], _z.C0.B0.A0[1]) + binary.BigEndian.PutUint64(r[552:560], _z.C0.B0.A0[2]) + binary.BigEndian.PutUint64(r[544:552], _z.C0.B0.A0[3]) + binary.BigEndian.PutUint64(r[536:544], _z.C0.B0.A0[4]) + binary.BigEndian.PutUint64(r[528:536], _z.C0.B0.A0[5]) + + binary.BigEndian.PutUint64(r[520:528], _z.C0.B0.A1[0]) + binary.BigEndian.PutUint64(r[512:520], _z.C0.B0.A1[1]) + binary.BigEndian.PutUint64(r[504:512], _z.C0.B0.A1[2]) + binary.BigEndian.PutUint64(r[496:504], _z.C0.B0.A1[3]) + binary.BigEndian.PutUint64(r[488:496], _z.C0.B0.A1[4]) + binary.BigEndian.PutUint64(r[480:488], _z.C0.B0.A1[5]) + + binary.BigEndian.PutUint64(r[472:480], _z.C0.B1.A0[0]) + binary.BigEndian.PutUint64(r[464:472], _z.C0.B1.A0[1]) + binary.BigEndian.PutUint64(r[456:464], _z.C0.B1.A0[2]) + binary.BigEndian.PutUint64(r[448:456], _z.C0.B1.A0[3]) + binary.BigEndian.PutUint64(r[440:448], _z.C0.B1.A0[4]) + binary.BigEndian.PutUint64(r[432:440], _z.C0.B1.A0[5]) + + binary.BigEndian.PutUint64(r[424:432], _z.C0.B1.A1[0]) + binary.BigEndian.PutUint64(r[416:424], _z.C0.B1.A1[1]) + binary.BigEndian.PutUint64(r[408:416], _z.C0.B1.A1[2]) + binary.BigEndian.PutUint64(r[400:408], _z.C0.B1.A1[3]) + binary.BigEndian.PutUint64(r[392:400], _z.C0.B1.A1[4]) + binary.BigEndian.PutUint64(r[384:392], _z.C0.B1.A1[5]) + + binary.BigEndian.PutUint64(r[376:384], _z.C0.B2.A0[0]) + binary.BigEndian.PutUint64(r[368:376], _z.C0.B2.A0[1]) + binary.BigEndian.PutUint64(r[360:368], _z.C0.B2.A0[2]) + binary.BigEndian.PutUint64(r[352:360], _z.C0.B2.A0[3]) + binary.BigEndian.PutUint64(r[344:352], _z.C0.B2.A0[4]) + binary.BigEndian.PutUint64(r[336:344], _z.C0.B2.A0[5]) + + binary.BigEndian.PutUint64(r[328:336], _z.C0.B2.A1[0]) + binary.BigEndian.PutUint64(r[320:328], _z.C0.B2.A1[1]) + binary.BigEndian.PutUint64(r[312:320], _z.C0.B2.A1[2]) + binary.BigEndian.PutUint64(r[304:312], _z.C0.B2.A1[3]) + binary.BigEndian.PutUint64(r[296:304], _z.C0.B2.A1[4]) + binary.BigEndian.PutUint64(r[288:296], _z.C0.B2.A1[5]) + + binary.BigEndian.PutUint64(r[280:288], _z.C1.B0.A0[0]) + binary.BigEndian.PutUint64(r[272:280], _z.C1.B0.A0[1]) + binary.BigEndian.PutUint64(r[264:272], _z.C1.B0.A0[2]) + binary.BigEndian.PutUint64(r[256:264], _z.C1.B0.A0[3]) + binary.BigEndian.PutUint64(r[248:256], _z.C1.B0.A0[4]) + binary.BigEndian.PutUint64(r[240:248], _z.C1.B0.A0[5]) + + binary.BigEndian.PutUint64(r[232:240], _z.C1.B0.A1[0]) + binary.BigEndian.PutUint64(r[224:232], _z.C1.B0.A1[1]) + binary.BigEndian.PutUint64(r[216:224], _z.C1.B0.A1[2]) + binary.BigEndian.PutUint64(r[208:216], _z.C1.B0.A1[3]) + binary.BigEndian.PutUint64(r[200:208], _z.C1.B0.A1[4]) + binary.BigEndian.PutUint64(r[192:200], _z.C1.B0.A1[5]) + + binary.BigEndian.PutUint64(r[184:192], _z.C1.B1.A0[0]) + binary.BigEndian.PutUint64(r[176:184], _z.C1.B1.A0[1]) + binary.BigEndian.PutUint64(r[168:176], _z.C1.B1.A0[2]) + binary.BigEndian.PutUint64(r[160:168], _z.C1.B1.A0[3]) + binary.BigEndian.PutUint64(r[152:160], _z.C1.B1.A0[4]) + binary.BigEndian.PutUint64(r[144:152], _z.C1.B1.A0[5]) + + binary.BigEndian.PutUint64(r[136:144], _z.C1.B1.A1[0]) + binary.BigEndian.PutUint64(r[128:136], _z.C1.B1.A1[1]) + binary.BigEndian.PutUint64(r[120:128], _z.C1.B1.A1[2]) + binary.BigEndian.PutUint64(r[112:120], _z.C1.B1.A1[3]) + binary.BigEndian.PutUint64(r[104:112], _z.C1.B1.A1[4]) + binary.BigEndian.PutUint64(r[96:104], _z.C1.B1.A1[5]) + + binary.BigEndian.PutUint64(r[88:96], _z.C1.B2.A0[0]) + binary.BigEndian.PutUint64(r[80:88], _z.C1.B2.A0[1]) + binary.BigEndian.PutUint64(r[72:80], _z.C1.B2.A0[2]) + binary.BigEndian.PutUint64(r[64:72], _z.C1.B2.A0[3]) + binary.BigEndian.PutUint64(r[56:64], _z.C1.B2.A0[4]) + binary.BigEndian.PutUint64(r[48:56], _z.C1.B2.A0[5]) + + binary.BigEndian.PutUint64(r[40:48], _z.C1.B2.A1[0]) + binary.BigEndian.PutUint64(r[32:40], _z.C1.B2.A1[1]) + binary.BigEndian.PutUint64(r[24:32], _z.C1.B2.A1[2]) + binary.BigEndian.PutUint64(r[16:24], _z.C1.B2.A1[3]) + binary.BigEndian.PutUint64(r[8:16], _z.C1.B2.A1[4]) + binary.BigEndian.PutUint64(r[0:8], _z.C1.B2.A1[5]) + + return +} + +// SetBytes interprets e as the bytes of a big-endian GT +// sets z to that value (in Montgomery form), and returns z. +// size(e) == 48 * 12 +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) SetBytes(e []byte) error { + if len(e) != SizeOfGT { + return errors.New("invalid buffer size") + } + z.C0.B0.A0.SetBytes(e[528 : 528+fp.Bytes]) + + z.C0.B0.A1.SetBytes(e[480 : 480+fp.Bytes]) + + z.C0.B1.A0.SetBytes(e[432 : 432+fp.Bytes]) + + z.C0.B1.A1.SetBytes(e[384 : 384+fp.Bytes]) + + z.C0.B2.A0.SetBytes(e[336 : 336+fp.Bytes]) + + z.C0.B2.A1.SetBytes(e[288 : 288+fp.Bytes]) + + z.C1.B0.A0.SetBytes(e[240 : 240+fp.Bytes]) + + z.C1.B0.A1.SetBytes(e[192 : 192+fp.Bytes]) + + z.C1.B1.A0.SetBytes(e[144 : 144+fp.Bytes]) + + z.C1.B1.A1.SetBytes(e[96 : 96+fp.Bytes]) + + z.C1.B2.A0.SetBytes(e[48 : 48+fp.Bytes]) + + z.C1.B2.A1.SetBytes(e[0 : 0+fp.Bytes]) + + return nil +} + +// IsInSubGroup ensures GT/E12 is in correct sugroup +func (z *E12) IsInSubGroup() bool { + var a, b E12 + + // check z^(Phi_k(p)) == 1 + a.FrobeniusSquare(z) + b.FrobeniusSquare(&a).Mul(&b, z) + + if !a.Equal(&b) { + return false + } + + // check z^(p+1-t) == 1 + a.Frobenius(z) + b.Expt(z) + + return a.Equal(&b) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go new file mode 100644 index 0000000000..55c9328795 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go @@ -0,0 +1,63 @@ +package fptower + +func (z *E12) nSquare(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquare(z) + } +} + +func (z *E12) nSquareCompressed(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquareCompressed(z) + } +} + +// Expt set z to x^t in E12 and return z +func (z *E12) Expt(x *E12) *E12 { + // const tAbsVal uint64 = 9586122913090633729 + // tAbsVal in binary: 1000010100001000110000000000000000000000000000000000000000000001 + // drop the low 46 bits (all 0 except the least significant bit): 100001010000100011 = 136227 + // Shortest addition chains can be found at https://wwwhomes.uni-bielefeld.de/achim/addition_chain.html + + var result, x33 E12 + + // a shortest addition chain for 136227 + result.Set(x) + result.nSquare(5) + result.Mul(&result, x) + x33.Set(&result) + result.nSquare(7) + result.Mul(&result, &x33) + result.nSquare(4) + result.Mul(&result, x) + result.CyclotomicSquare(&result) + result.Mul(&result, x) + + // the remaining 46 bits + result.nSquareCompressed(46) + result.Decompress(&result) + result.Mul(&result, x) + + z.Set(&result) + return z +} + +// MulBy034 multiplication by sparse element (c0,0,0,c3,c4,0) +func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { + + var a, b, d E6 + + a.MulByE2(&z.C0, c0) + + b.Set(&z.C1) + b.MulBy01(c3, c4) + + c0.Add(c0, c3) + d.Add(&z.C0, &z.C1) + d.MulBy01(c0, c4) + + z.C1.Add(&a, &b).Neg(&z.C1).Add(&z.C1, &d) + z.C0.MulByNonResidue(&b).Add(&z.C0, &a) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go new file mode 100644 index 0000000000..d24ab06d22 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go @@ -0,0 +1,262 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "math/big" +) + +// E2 is a degree two finite field extension of fp.Element +type E2 struct { + A0, A1 fp.Element +} + +// Equal returns true if z equals x, fasle otherwise +func (z *E2) Equal(x *E2) bool { + return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +// +func (z *E2) Cmp(x *E2) int { + if a1 := z.A1.Cmp(&x.A1); a1 != 0 { + return a1 + } + return z.A0.Cmp(&x.A0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E2) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.A1.IsZero() { + return z.A0.LexicographicallyLargest() + } + return z.A1.LexicographicallyLargest() +} + +// SetString sets a E2 element from strings +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z +} + +// SetZero sets an E2 elmt to zero +func (z *E2) SetZero() *E2 { + z.A0.SetZero() + z.A1.SetZero() + return z +} + +// Set sets an E2 from x +func (z *E2) Set(x *E2) *E2 { + z.A0 = x.A0 + z.A1 = x.A1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E2) SetOne() *E2 { + z.A0.SetOne() + z.A1.SetZero() + return z +} + +// SetRandom sets a0 and a1 to random values +func (z *E2) SetRandom() (*E2, error) { + if _, err := z.A0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.A1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, fasle otherwise +func (z *E2) IsZero() bool { + return z.A0.IsZero() && z.A1.IsZero() +} + +// Add adds two elements of E2 +func (z *E2) Add(x, y *E2) *E2 { + addE2(z, x, y) + return z +} + +// Sub two elements of E2 +func (z *E2) Sub(x, y *E2) *E2 { + subE2(z, x, y) + return z +} + +// Double doubles an E2 element +func (z *E2) Double(x *E2) *E2 { + doubleE2(z, x) + return z +} + +// Neg negates an E2 element +func (z *E2) Neg(x *E2) *E2 { + negE2(z, x) + return z +} + +// String implements Stringer interface for fancy printing +func (z *E2) String() string { + return (z.A0.String() + "+" + z.A1.String() + "*u") +} + +// ToMont converts to mont form +func (z *E2) ToMont() *E2 { + z.A0.ToMont() + z.A1.ToMont() + return z +} + +// FromMont converts from mont form +func (z *E2) FromMont() *E2 { + z.A0.FromMont() + z.A1.FromMont() + return z +} + +// MulByElement multiplies an element in E2 by an element in fp +func (z *E2) MulByElement(x *E2, y *fp.Element) *E2 { + var yCopy fp.Element + yCopy.Set(y) + z.A0.Mul(&x.A0, &yCopy) + z.A1.Mul(&x.A1, &yCopy) + return z +} + +// Conjugate conjugates an element in E2 +func (z *E2) Conjugate(x *E2) *E2 { + z.A0 = x.A0 + z.A1.Neg(&x.A1) + return z +} + +// Halve sets z = z / 2 +func (z *E2) Halve() { + z.A0.Halve() + z.A1.Halve() +} + +// Legendre returns the Legendre symbol of z +func (z *E2) Legendre() int { + var n fp.Element + z.norm(&n) + return n.Legendre() +} + +// Exp sets z=x**e and returns it +func (z *E2) Exp(x E2, exponent *big.Int) *E2 { + z.SetOne() + b := exponent.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Sqrt sets z to the square root of and returns z +// The function does not test wether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E2) Sqrt(x *E2) *E2 { + + // precomputation + var b, c, d, e, f, x0 E2 + var _b, o fp.Element + + // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + c.A1.SetOne() + + q := fp.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e) + + return z +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []E2) []E2 { + res := make([]E2, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E2 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go new file mode 100644 index 0000000000..556e5eef0c --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go @@ -0,0 +1,45 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// q (modulus) +var qE2 = [6]uint64{ + 9586122913090633729, + 1660523435060625408, + 2230234197602682880, + 1883307231910630287, + 14284016967150029115, + 121098312706494698, +} + +// q'[0], see montgommery multiplication algorithm +var ( + qE2Inv0 uint64 = 9586122913090633727 + _ = qE2Inv0 // used in asm +) + +//go:noescape +func addE2(res, x, y *E2) + +//go:noescape +func subE2(res, x, y *E2) + +//go:noescape +func doubleE2(res, x *E2) + +//go:noescape +func negE2(res, x *E2) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s new file mode 100644 index 0000000000..053bd8ded1 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s @@ -0,0 +1,320 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +TEXT ·addE2(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ y+16(FP), DX + ADDQ 0(DX), BX + ADCQ 8(DX), SI + ADCQ 16(DX), DI + ADCQ 24(DX), R8 + ADCQ 32(DX), R9 + ADCQ 40(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ res+0(FP), CX + MOVQ BX, 0(CX) + MOVQ SI, 8(CX) + MOVQ DI, 16(CX) + MOVQ R8, 24(CX) + MOVQ R9, 32(CX) + MOVQ R10, 40(CX) + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + ADDQ 48(DX), BX + ADCQ 56(DX), SI + ADCQ 64(DX), DI + ADCQ 72(DX), R8 + ADCQ 80(DX), R9 + ADCQ 88(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ BX, 48(CX) + MOVQ SI, 56(CX) + MOVQ DI, 64(CX) + MOVQ R8, 72(CX) + MOVQ R9, 80(CX) + MOVQ R10, 88(CX) + RET + +TEXT ·doubleE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 0(DX) + MOVQ BX, 8(DX) + MOVQ SI, 16(DX) + MOVQ DI, 24(DX) + MOVQ R8, 32(DX) + MOVQ R9, 40(DX) + MOVQ 48(AX), CX + MOVQ 56(AX), BX + MOVQ 64(AX), SI + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 48(DX) + MOVQ BX, 56(DX) + MOVQ SI, 64(DX) + MOVQ DI, 72(DX) + MOVQ R8, 80(DX) + MOVQ R9, 88(DX) + RET + +TEXT ·subE2(SB), NOSPLIT, $0-24 + XORQ R9, R9 + MOVQ x+8(FP), R8 + MOVQ 0(R8), AX + MOVQ 8(R8), DX + MOVQ 16(R8), CX + MOVQ 24(R8), BX + MOVQ 32(R8), SI + MOVQ 40(R8), DI + MOVQ y+16(FP), R8 + SUBQ 0(R8), AX + SBBQ 8(R8), DX + SBBQ 16(R8), CX + SBBQ 24(R8), BX + SBBQ 32(R8), SI + SBBQ 40(R8), DI + MOVQ x+8(FP), R8 + MOVQ $0x8508c00000000001, R10 + MOVQ $0x170b5d4430000000, R11 + MOVQ $0x1ef3622fba094800, R12 + MOVQ $0x1a22d9f300f5138f, R13 + MOVQ $0xc63b05c06ca1493b, R14 + MOVQ $0x01ae3a4617c510ea, R15 + CMOVQCC R9, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + ADDQ R10, AX + ADCQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + ADCQ R15, DI + MOVQ res+0(FP), R10 + MOVQ AX, 0(R10) + MOVQ DX, 8(R10) + MOVQ CX, 16(R10) + MOVQ BX, 24(R10) + MOVQ SI, 32(R10) + MOVQ DI, 40(R10) + MOVQ 48(R8), AX + MOVQ 56(R8), DX + MOVQ 64(R8), CX + MOVQ 72(R8), BX + MOVQ 80(R8), SI + MOVQ 88(R8), DI + MOVQ y+16(FP), R8 + SUBQ 48(R8), AX + SBBQ 56(R8), DX + SBBQ 64(R8), CX + SBBQ 72(R8), BX + SBBQ 80(R8), SI + SBBQ 88(R8), DI + MOVQ $0x8508c00000000001, R11 + MOVQ $0x170b5d4430000000, R12 + MOVQ $0x1ef3622fba094800, R13 + MOVQ $0x1a22d9f300f5138f, R14 + MOVQ $0xc63b05c06ca1493b, R15 + MOVQ $0x01ae3a4617c510ea, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + CMOVQCC R9, R10 + ADDQ R11, AX + ADCQ R12, DX + ADCQ R13, CX + ADCQ R14, BX + ADCQ R15, SI + ADCQ R10, DI + MOVQ res+0(FP), R8 + MOVQ AX, 48(R8) + MOVQ DX, 56(R8) + MOVQ CX, 64(R8) + MOVQ BX, 72(R8) + MOVQ SI, 80(R8) + MOVQ DI, 88(R8) + RET + +TEXT ·negE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l1 + MOVQ AX, 0(DX) + MOVQ AX, 8(DX) + MOVQ AX, 16(DX) + MOVQ AX, 24(DX) + MOVQ AX, 32(DX) + MOVQ AX, 40(DX) + JMP l3 + +l1: + MOVQ $0x8508c00000000001, CX + SUBQ BX, CX + MOVQ CX, 0(DX) + MOVQ $0x170b5d4430000000, CX + SBBQ SI, CX + MOVQ CX, 8(DX) + MOVQ $0x1ef3622fba094800, CX + SBBQ DI, CX + MOVQ CX, 16(DX) + MOVQ $0x1a22d9f300f5138f, CX + SBBQ R8, CX + MOVQ CX, 24(DX) + MOVQ $0xc63b05c06ca1493b, CX + SBBQ R9, CX + MOVQ CX, 32(DX) + MOVQ $0x01ae3a4617c510ea, CX + SBBQ R10, CX + MOVQ CX, 40(DX) + +l3: + MOVQ x+8(FP), AX + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l2 + MOVQ AX, 48(DX) + MOVQ AX, 56(DX) + MOVQ AX, 64(DX) + MOVQ AX, 72(DX) + MOVQ AX, 80(DX) + MOVQ AX, 88(DX) + RET + +l2: + MOVQ $0x8508c00000000001, CX + SUBQ BX, CX + MOVQ CX, 48(DX) + MOVQ $0x170b5d4430000000, CX + SBBQ SI, CX + MOVQ CX, 56(DX) + MOVQ $0x1ef3622fba094800, CX + SBBQ DI, CX + MOVQ CX, 64(DX) + MOVQ $0x1a22d9f300f5138f, CX + SBBQ R8, CX + MOVQ CX, 72(DX) + MOVQ $0xc63b05c06ca1493b, CX + SBBQ R9, CX + MOVQ CX, 80(DX) + MOVQ $0x01ae3a4617c510ea, CX + SBBQ R10, CX + MOVQ CX, 88(DX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go new file mode 100644 index 0000000000..be7ece22fe --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go @@ -0,0 +1,106 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" +) + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + var a, b, c fp.Element + a.Add(&x.A0, &x.A1) + b.Add(&y.A0, &y.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &y.A0) + c.Mul(&x.A1, &y.A1) + z.A1.Sub(&a, &b).Sub(&z.A1, &c) + fp.MulBy5(&c) + z.A0.Sub(&b, &c) + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { + //algo 22 https://eprint.iacr.org/2010/354.pdf + var c0, c2 fp.Element + c0.Add(&x.A0, &x.A1) + c2.Neg(&x.A1) + fp.MulBy5(&c2) + c2.Add(&c2, &x.A0) + + c0.Mul(&c0, &c2) // (x1+x2)*(x1+(u**2)x2) + c2.Mul(&x.A0, &x.A1).Double(&c2) + z.A1 = c2 + c2.Double(&c2) + z.A0.Add(&c0, &c2) + + return z +} + +// MulByNonResidue multiplies a E2 by (0,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + a := x.A0 + b := x.A1 // fetching x.A1 in the function below is slower + fp.MulBy5(&b) + z.A0.Neg(&b) + z.A1 = a + return z +} + +// MulByNonResidueInv multiplies a E2 by (0,1)^{-1} +func (z *E2) MulByNonResidueInv(x *E2) *E2 { + //z.A1.MulByNonResidueInv(&x.A0) + a := x.A1 + fiveinv := fp.Element{ + 330620507644336508, + 9878087358076053079, + 11461392860540703536, + 6973035786057818995, + 8846909097162646007, + 104838758629667239, + } + z.A1.Mul(&x.A0, &fiveinv).Neg(&z.A1) + z.A0 = a + return z +} + +// Inverse sets z to the E2-inverse of x, returns z +func (z *E2) Inverse(x *E2) *E2 { + // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf + //var a, b, t0, t1, tmp fp.Element + var t0, t1, tmp fp.Element + a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below + b := &x.A1 + t0.Square(a) + t1.Square(b) + tmp.Set(&t1) + fp.MulBy5(&tmp) + t0.Add(&t0, &tmp) + t1.Inverse(&t0) + z.A0.Mul(a, &t1) + z.A1.Mul(b, &t1).Neg(&z.A1) + + return z +} + +// norm sets x to the norm of z +func (z *E2) norm(x *fp.Element) { + var tmp fp.Element + x.Square(&z.A1) + tmp.Set(x) + fp.MulBy5(&tmp) + x.Square(&z.A0).Add(x, &tmp) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go new file mode 100644 index 0000000000..0ce4d83334 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go @@ -0,0 +1,40 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +func addE2(z, x, y *E2) { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) +} + +func subE2(z, x, y *E2) { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) +} + +func doubleE2(z, x *E2) { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) +} + +func negE2(z, x *E2) { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go new file mode 100644 index 0000000000..adc33ceefd --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go @@ -0,0 +1,264 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// E6 is a degree three finite field extension of fp2 +type E6 struct { + B0, B1, B2 E2 +} + +// Equal returns true if z equals x, fasle otherwise +func (z *E6) Equal(x *E6) bool { + return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) && z.B2.Equal(&x.B2) +} + +// SetString sets a E6 elmt from stringf +func (z *E6) SetString(s1, s2, s3, s4, s5, s6 string) *E6 { + z.B0.SetString(s1, s2) + z.B1.SetString(s3, s4) + z.B2.SetString(s5, s6) + return z +} + +// Set Sets a E6 elmt form another E6 elmt +func (z *E6) Set(x *E6) *E6 { + z.B0 = x.B0 + z.B1 = x.B1 + z.B2 = x.B2 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E6) SetOne() *E6 { + *z = E6{} + z.B0.A0.SetOne() + return z +} + +// SetRandom set z to a random elmt +func (z *E6) SetRandom() (*E6, error) { + if _, err := z.B0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B1.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B2.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// ToMont converts to Mont form +func (z *E6) ToMont() *E6 { + z.B0.ToMont() + z.B1.ToMont() + z.B2.ToMont() + return z +} + +// FromMont converts from Mont form +func (z *E6) FromMont() *E6 { + z.B0.FromMont() + z.B1.FromMont() + z.B2.FromMont() + return z +} + +// Add adds two elements of E6 +func (z *E6) Add(x, y *E6) *E6 { + z.B0.Add(&x.B0, &y.B0) + z.B1.Add(&x.B1, &y.B1) + z.B2.Add(&x.B2, &y.B2) + return z +} + +// Neg negates the E6 number +func (z *E6) Neg(x *E6) *E6 { + z.B0.Neg(&x.B0) + z.B1.Neg(&x.B1) + z.B2.Neg(&x.B2) + return z +} + +// Sub two elements of E6 +func (z *E6) Sub(x, y *E6) *E6 { + z.B0.Sub(&x.B0, &y.B0) + z.B1.Sub(&x.B1, &y.B1) + z.B2.Sub(&x.B2, &y.B2) + return z +} + +// Double doubles an element in E6 +func (z *E6) Double(x *E6) *E6 { + z.B0.Double(&x.B0) + z.B1.Double(&x.B1) + z.B2.Double(&x.B2) + return z +} + +// String puts E6 elmt in string form +func (z *E6) String() string { + return (z.B0.String() + "+(" + z.B1.String() + ")*v+(" + z.B2.String() + ")*v**2") +} + +// MulByNonResidue mul x by (0,1,0) +func (z *E6) MulByNonResidue(x *E6) *E6 { + z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z.B0.MulByNonResidue(&z.B0) + return z +} + +// MulByE2 multiplies an element in E6 by an element in E2 +func (z *E6) MulByE2(x *E6, y *E2) *E6 { + var yCopy E2 + yCopy.Set(y) + z.B0.Mul(&x.B0, &yCopy) + z.B1.Mul(&x.B1, &yCopy) + z.B2.Mul(&x.B2, &yCopy) + return z +} + +// MulBy01 multiplication by sparse element (c0,c1,0) +func (z *E6) MulBy01(c0, c1 *E2) *E6 { + + var a, b, tmp, t0, t1, t2 E2 + + a.Mul(&z.B0, c0) + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + t0.Add(&t0, &a) + + tmp.Add(&z.B0, &z.B2) + t2.Mul(c0, &tmp) + t2.Sub(&t2, &a) + t2.Add(&t2, &b) + + t1.Add(c0, c1) + tmp.Add(&z.B0, &z.B1) + t1.Mul(&t1, &tmp) + t1.Sub(&t1, &a) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&t2) + + return z +} + +// MulBy1 multiplication of E6 by sparse element (0, c1, 0) +func (z *E6) MulBy1(c1 *E2) *E6 { + + var b, tmp, t0, t1 E2 + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + + tmp.Add(&z.B0, &z.B1) + t1.Mul(c1, &tmp) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&b) + + return z +} + +// Mul sets z to the E6 product of x,y, returns z +func (z *E6) Mul(x, y *E6) *E6 { + // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + var t0, t1, t2, c0, c1, c2, tmp E2 + t0.Mul(&x.B0, &y.B0) + t1.Mul(&x.B1, &y.B1) + t2.Mul(&x.B2, &y.B2) + + c0.Add(&x.B1, &x.B2) + tmp.Add(&y.B1, &y.B2) + c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) + + c1.Add(&x.B0, &x.B1) + tmp.Add(&y.B0, &y.B1) + c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + + tmp.Add(&x.B0, &x.B2) + c2.Add(&y.B0, &y.B2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) + + z.B0.Set(&c0) + z.B1.Set(&c1) + z.B2.Set(&c2) + + return z +} + +// Square sets z to the E6 product of x,x, returns z +func (z *E6) Square(x *E6) *E6 { + + // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf + var c4, c5, c1, c2, c3, c0 E2 + c4.Mul(&x.B0, &x.B1).Double(&c4) + c5.Square(&x.B2) + c1.MulByNonResidue(&c5).Add(&c1, &c4) + c2.Sub(&c4, &c5) + c3.Square(&x.B0) + c4.Sub(&x.B0, &x.B1).Add(&c4, &x.B2) + c5.Mul(&x.B1, &x.B2).Double(&c5) + c4.Square(&c4) + c0.MulByNonResidue(&c5).Add(&c0, &c3) + z.B2.Add(&c2, &c4).Add(&z.B2, &c5).Sub(&z.B2, &c3) + z.B0.Set(&c0) + z.B1.Set(&c1) + + return z +} + +// Inverse an element in E6 +func (z *E6) Inverse(x *E6) *E6 { + // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf + // step 9 is wrong in the paper it's t1-t4 + var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0.Square(&x.B0) + t1.Square(&x.B1) + t2.Square(&x.B2) + t3.Mul(&x.B0, &x.B1) + t4.Mul(&x.B0, &x.B2) + t5.Mul(&x.B1, &x.B2) + c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) + c1.MulByNonResidue(&t2).Sub(&c1, &t3) + c2.Sub(&t1, &t4) + t6.Mul(&x.B0, &c0) + d1.Mul(&x.B2, &c1) + d2.Mul(&x.B1, &c2) + d1.Add(&d1, &d2).MulByNonResidue(&d1) + t6.Add(&t6, &d1) + t6.Inverse(&t6) + z.B0.Mul(&c0, &t6) + z.B1.Mul(&c1, &t6) + z.B2.Mul(&c2, &t6) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go new file mode 100644 index 0000000000..d5b8350129 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go @@ -0,0 +1,327 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + +// Frobenius set z to Frobenius(x), return z +func (z *E12) Frobenius(x *E12) *E12 { + // Algorithm 28 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + // Frobenius acts on fp2 by conjugation + t[0].Conjugate(&x.C0.B0) + t[1].Conjugate(&x.C0.B1) + t[2].Conjugate(&x.C0.B2) + t[3].Conjugate(&x.C1.B0) + t[4].Conjugate(&x.C1.B1) + t[5].Conjugate(&x.C1.B2) + + t[1].MulByNonResidue1Power2(&t[1]) + t[2].MulByNonResidue1Power4(&t[2]) + t[3].MulByNonResidue1Power1(&t[3]) + t[4].MulByNonResidue1Power3(&t[4]) + t[5].MulByNonResidue1Power5(&t[5]) + + z.C0.B0 = t[0] + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// FrobeniusSquare set z to Frobenius^2(x), and return z +func (z *E12) FrobeniusSquare(x *E12) *E12 { + // Algorithm 29 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + t[1].MulByNonResidue2Power2(&x.C0.B1) + t[2].MulByNonResidue2Power4(&x.C0.B2) + t[3].MulByNonResidue2Power1(&x.C1.B0) + t[4].MulByNonResidue2Power3(&x.C1.B1) + t[5].MulByNonResidue2Power5(&x.C1.B2) + + z.C0.B0 = x.C0.B0 + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// FrobeniusCube set z to Frobenius^3(x), return z +func (z *E12) FrobeniusCube(x *E12) *E12 { + // Algorithm 30 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + // Frobenius^3 acts on fp2 by conjugation + t[0].Conjugate(&x.C0.B0) + t[1].Conjugate(&x.C0.B1) + t[2].Conjugate(&x.C0.B2) + t[3].Conjugate(&x.C1.B0) + t[4].Conjugate(&x.C1.B1) + t[5].Conjugate(&x.C1.B2) + + t[1].MulByNonResidue3Power2(&t[1]) + t[2].MulByNonResidue3Power4(&t[2]) + t[3].MulByNonResidue3Power1(&t[3]) + t[4].MulByNonResidue3Power3(&t[4]) + t[5].MulByNonResidue3Power5(&t[5]) + + z.C0.B0 = t[0] + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// MulByNonResidue1Power1 set z=x*(0,1)^(1*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power1(x *E2) *E2 { + // 92949345220277864758624960506473182677953048909283248980960104381795901929519566951595905490535835115111760994353 + b := fp.Element{ + 7981638599956744862, + 11830407261614897732, + 6308788297503259939, + 10596665404780565693, + 11693741422477421038, + 61545186993886319, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power2 set z=x*(0,1)^(2*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power2(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 + b := fp.Element{ + 6382252053795993818, + 1383562296554596171, + 11197251941974877903, + 6684509567199238270, + 6699184357838251020, + 19987743694136192, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power3 set z=x*(0,1)^(3*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power3(x *E2) *E2 { + // 216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499 + b := fp.Element{ + 10965161018967488287, + 18251363109856037426, + 7036083669251591763, + 16109345360066746489, + 4679973768683352764, + 96952949334633821, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power4 set z=x*(0,1)^(4*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power4(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 + b := fp.Element{ + 15766275933608376691, + 15635974902606112666, + 1934946774703877852, + 18129354943882397960, + 15437979634065614942, + 101285514078273488, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power5 set z=x*(0,1)^(5*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power5(x *E2) *E2 { + // 123516416119946754630746545296132064952198520638002533875843642777304321125866014634106496325844844051843001220146 + b := fp.Element{ + 2983522419010743425, + 6420955848241139694, + 727295371748331824, + 5512679955286180796, + 11432976419915483342, + 35407762340747501, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power1 set z=x*(0,1)^(1*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power1(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 + b := fp.Element{ + 6382252053795993818, + 1383562296554596171, + 11197251941974877903, + 6684509567199238270, + 6699184357838251020, + 19987743694136192, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power2 set z=x*(0,1)^(2*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power2(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 + b := fp.Element{ + 15766275933608376691, + 15635974902606112666, + 1934946774703877852, + 18129354943882397960, + 15437979634065614942, + 101285514078273488, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power3 set z=x*(0,1)^(3*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power3(x *E2) *E2 { + // 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176 + b := fp.Element{ + 9384023879812382873, + 14252412606051516495, + 9184438906438551565, + 11444845376683159689, + 8738795276227363922, + 81297770384137296, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power4 set z=x*(0,1)^(4*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power4(x *E2) *E2 { + // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047231 + b := fp.Element{ + 3203870859294639911, + 276961138506029237, + 9479726329337356593, + 13645541738420943632, + 7584832609311778094, + 101110569012358506, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power5 set z=x*(0,1)^(5*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power5(x *E2) *E2 { + // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047232 + b := fp.Element{ + 12266591053191808654, + 4471292606164064357, + 295287422898805027, + 2200696361737783943, + 17292781406793965788, + 19812798628221209, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue3Power1 set z=x*(0,1)^(1*(p^3-1)/6) and return z +func (z *E2) MulByNonResidue3Power1(x *E2) *E2 { + // 216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499 + b := fp.Element{ + 10965161018967488287, + 18251363109856037426, + 7036083669251591763, + 16109345360066746489, + 4679973768683352764, + 96952949334633821, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue3Power2 set z=x*(0,1)^(2*(p^3-1)/6) and return z +func (z *E2) MulByNonResidue3Power2(x *E2) *E2 { + // 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176 + b := fp.Element{ + 9384023879812382873, + 14252412606051516495, + 9184438906438551565, + 11444845376683159689, + 8738795276227363922, + 81297770384137296, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue3Power3 set z=x*(0,1)^(3*(p^3-1)/6) and return z +func (z *E2) MulByNonResidue3Power3(x *E2) *E2 { + // 42198664672744474621281227892288285906241943207628877683080515507620245292955241189266486323192680957485559243678 + b := fp.Element{ + 17067705967832697058, + 1855904398914139597, + 13640894602060642732, + 4220705945553435413, + 9604043198466676350, + 24145363371860877, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue3Power4 set z=x*(0,1)^(4*(p^3-1)/6) and return z +func (z *E2) MulByNonResidue3Power4(x *E2) *E2 { + // 1 + // nothing to do + return z +} + +// MulByNonResidue3Power5 set z=x*(0,1)^(5*(p^3-1)/6) and return z +func (z *E2) MulByNonResidue3Power5(x *E2) *E2 { + // 216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499 + b := fp.Element{ + 10965161018967488287, + 18251363109856037426, + 7036083669251591763, + 16109345360066746489, + 4679973768683352764, + 96952949334633821, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go new file mode 100644 index 0000000000..7efecf0d41 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go @@ -0,0 +1,1160 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "encoding/binary" + "errors" + "io" + "reflect" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" +) + +// To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity +// metadata needed for point (de)compression +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +const ( + mMask byte = 0b111 << 5 + mUncompressed byte = 0b000 << 5 + mUncompressedInfinity byte = 0b010 << 5 + mCompressedSmallest byte = 0b100 << 5 + mCompressedLargest byte = 0b101 << 5 + mCompressedInfinity byte = 0b110 << 5 +) + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = fptower.SizeOfGT + +// Encoder writes bls12-377 object values to an output stream +type Encoder struct { + w io.Writer + n int64 // written bytes + raw bool // raw vs compressed encoding +} + +// Decoder reads bls12-377 object values from an inbound stream +type Decoder struct { + r io.Reader + n int64 // read bytes + subGroupCheck bool // default to true +} + +// NewDecoder returns a binary decoder supporting curve bls12-377 objects in both +// compressed and uncompressed (raw) forms +func NewDecoder(r io.Reader, options ...func(*Decoder)) *Decoder { + d := &Decoder{r: r, subGroupCheck: true} + + for _, o := range options { + o(d) + } + + return d +} + +// Decode reads the binary encoding of v from the stream +// type must be *uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, *[]G1Affine or *[]G2Affine +func (dec *Decoder) Decode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { + return errors.New("bls12-377 decoder: unsupported type, need pointer") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // in particular, careful attention must be given to usage of Bytes() method on Elements and Points + // that return an array (not a slice) of bytes. Using this is beneficial to minimize memallocs + // in very large (de)serialization upstream in gnark. + // (but detrimental to code lisibility here) + // TODO double check memory usage and factorize this + + var buf [SizeOfG2AffineUncompressed]byte + var read int + + switch t := v.(type) { + case *fr.Element: + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + t.SetBytes(buf[:fr.Bytes]) + return + case *fp.Element: + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + t.SetBytes(buf[:fp.Bytes]) + return + case *[]fr.Element: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]fr.Element, sliceLen) + } + + for i := 0; i < len(*t); i++ { + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + (*t)[i].SetBytes(buf[:fr.Bytes]) + } + return + case *[]fp.Element: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]fp.Element, sliceLen) + } + + for i := 0; i < len(*t); i++ { + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + (*t)[i].SetBytes(buf[:fp.Bytes]) + } + return + case *G1Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *G2Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *[]G1Affine: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]G1Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + compressed[i] = !((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])) + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + case *[]G2Affine: + var sliceLen uint32 + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]G2Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + compressed[i] = !((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])) + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New("bls12-377 encoder: unsupported type") + } + err = binary.Read(dec.r, binary.BigEndian, t) + if err == nil { + dec.n += int64(n) + } + return + } +} + +// BytesRead return total bytes read from reader +func (dec *Decoder) BytesRead() int64 { + return dec.n +} + +func (dec *Decoder) readUint32() (r uint32, err error) { + var read int + var buf [4]byte + read, err = io.ReadFull(dec.r, buf[:4]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint32(buf[:4]) + return +} + +func isCompressed(msb byte) bool { + mData := msb & mMask + return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) +} + +// NewEncoder returns a binary encoder supporting curve bls12-377 objects +func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { + // default settings + enc := &Encoder{ + w: w, + n: 0, + raw: false, + } + + // handle options + for _, option := range options { + option(enc) + } + + return enc +} + +// Encode writes the binary encoding of v to the stream +// type must be uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, []G1Affine or []G2Affine +func (enc *Encoder) Encode(v interface{}) (err error) { + if enc.raw { + return enc.encodeRaw(v) + } + return enc.encode(v) +} + +// BytesWritten return total bytes written on writer +func (enc *Encoder) BytesWritten() int64 { + return enc.n +} + +// RawEncoding returns an option to use in NewEncoder(...) which sets raw encoding mode to true +// points will not be compressed using this option +func RawEncoding() func(*Encoder) { + return func(enc *Encoder) { + enc.raw = true + } +} + +// NoSubgroupChecks returns an option to use in NewDecoder(...) which disable subgroup checks on the points +// the decoder will read. Use with caution, as crafted points from an untrusted source can lead to crypto-attacks. +func NoSubgroupChecks() func(*Decoder) { + return func(dec *Decoder) { + dec.subGroupCheck = false + } +} + +func (enc *Encoder) encode(v interface{}) (err error) { + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // TODO double check memory usage and factorize this + + var written int + switch t := v.(type) { + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case []fr.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fr.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []fp.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fp.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) encodeRaw(v interface{}) (err error) { + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // TODO double check memory usage and factorize this + + var written int + switch t := v.(type) { + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case []fr.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fr.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []fp.Element: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + var buf [fp.Bytes]byte + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +// SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed +const SizeOfG1AffineCompressed = 48 + +// SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed +const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G1Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an allias to SetBytes() +func (p *G1Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + // tmp is used to convert from montgomery representation to regular + var tmp fp.Element + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + tmp = p.X + tmp.FromMont() + binary.BigEndian.PutUint64(res[40:48], tmp[0]) + binary.BigEndian.PutUint64(res[32:40], tmp[1]) + binary.BigEndian.PutUint64(res[24:32], tmp[2]) + binary.BigEndian.PutUint64(res[16:24], tmp[3]) + binary.BigEndian.PutUint64(res[8:16], tmp[4]) + binary.BigEndian.PutUint64(res[0:8], tmp[5]) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // tmp is used to convert from montgomery representation to regular + var tmp fp.Element + + // not compressed + // we store the Y coordinate + tmp = p.Y + tmp.FromMont() + binary.BigEndian.PutUint64(res[88:96], tmp[0]) + binary.BigEndian.PutUint64(res[80:88], tmp[1]) + binary.BigEndian.PutUint64(res[72:80], tmp[2]) + binary.BigEndian.PutUint64(res[64:72], tmp[3]) + binary.BigEndian.PutUint64(res[56:64], tmp[4]) + binary.BigEndian.PutUint64(res[48:56], tmp[5]) + + // we store X and mask the most significant word with our metadata mask + tmp = p.X + tmp.FromMont() + binary.BigEndian.PutUint64(res[40:48], tmp[0]) + binary.BigEndian.PutUint64(res[32:40], tmp[1]) + binary.BigEndian.PutUint64(res[24:32], tmp[2]) + binary.BigEndian.PutUint64(res[16:24], tmp[3]) + binary.BigEndian.PutUint64(res[8:16], tmp[4]) + binary.BigEndian.PutUint64(res[0:8], tmp[5]) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// bytes in buf must match either RawBytes() or Bytes() output +// if buf is too short io.ErrShortBuffer is returned +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function retunrs an error +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G1Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG1AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG1AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // if infinity is encoded in the metadata, we don't need to read the buffer + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineCompressed, nil + } + if mData == mUncompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + p.X.SetBytes(buf[:fp.Bytes]) + p.Y.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + p.X.SetBytes(bufX[:fp.Bytes]) + + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + isInfinity = true + return + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + p.X.SetBytes(bufX[:fp.Bytes]) + // store mData in p.Y[0] + p.Y[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return +} + +// SizeOfG2AffineCompressed represents the size in bytes that a G2Affine need in binary form, compressed +const SizeOfG2AffineCompressed = 48 * 2 + +// SizeOfG2AffineUncompressed represents the size in bytes that a G2Affine need in binary form, uncompressed +const SizeOfG2AffineUncompressed = SizeOfG2AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G2Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an allias to SetBytes() +func (p *G2Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + // tmp is used to convert from montgomery representation to regular + var tmp fp.Element + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + tmp = p.X.A0 + tmp.FromMont() + binary.BigEndian.PutUint64(res[88:96], tmp[0]) + binary.BigEndian.PutUint64(res[80:88], tmp[1]) + binary.BigEndian.PutUint64(res[72:80], tmp[2]) + binary.BigEndian.PutUint64(res[64:72], tmp[3]) + binary.BigEndian.PutUint64(res[56:64], tmp[4]) + binary.BigEndian.PutUint64(res[48:56], tmp[5]) + + tmp = p.X.A1 + tmp.FromMont() + binary.BigEndian.PutUint64(res[40:48], tmp[0]) + binary.BigEndian.PutUint64(res[32:40], tmp[1]) + binary.BigEndian.PutUint64(res[24:32], tmp[2]) + binary.BigEndian.PutUint64(res[16:24], tmp[3]) + binary.BigEndian.PutUint64(res[8:16], tmp[4]) + binary.BigEndian.PutUint64(res[0:8], tmp[5]) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G2Affine) RawBytes() (res [SizeOfG2AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // tmp is used to convert from montgomery representation to regular + var tmp fp.Element + + // not compressed + // we store the Y coordinate + // p.Y.A1 | p.Y.A0 + tmp = p.Y.A0 + tmp.FromMont() + binary.BigEndian.PutUint64(res[184:192], tmp[0]) + binary.BigEndian.PutUint64(res[176:184], tmp[1]) + binary.BigEndian.PutUint64(res[168:176], tmp[2]) + binary.BigEndian.PutUint64(res[160:168], tmp[3]) + binary.BigEndian.PutUint64(res[152:160], tmp[4]) + binary.BigEndian.PutUint64(res[144:152], tmp[5]) + + tmp = p.Y.A1 + tmp.FromMont() + binary.BigEndian.PutUint64(res[136:144], tmp[0]) + binary.BigEndian.PutUint64(res[128:136], tmp[1]) + binary.BigEndian.PutUint64(res[120:128], tmp[2]) + binary.BigEndian.PutUint64(res[112:120], tmp[3]) + binary.BigEndian.PutUint64(res[104:112], tmp[4]) + binary.BigEndian.PutUint64(res[96:104], tmp[5]) + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + tmp = p.X.A1 + tmp.FromMont() + binary.BigEndian.PutUint64(res[40:48], tmp[0]) + binary.BigEndian.PutUint64(res[32:40], tmp[1]) + binary.BigEndian.PutUint64(res[24:32], tmp[2]) + binary.BigEndian.PutUint64(res[16:24], tmp[3]) + binary.BigEndian.PutUint64(res[8:16], tmp[4]) + binary.BigEndian.PutUint64(res[0:8], tmp[5]) + + tmp = p.X.A0 + tmp.FromMont() + binary.BigEndian.PutUint64(res[88:96], tmp[0]) + binary.BigEndian.PutUint64(res[80:88], tmp[1]) + binary.BigEndian.PutUint64(res[72:80], tmp[2]) + binary.BigEndian.PutUint64(res[64:72], tmp[3]) + binary.BigEndian.PutUint64(res[56:64], tmp[4]) + binary.BigEndian.PutUint64(res[48:56], tmp[5]) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// bytes in buf must match either RawBytes() or Bytes() output +// if buf is too short io.ErrShortBuffer is returned +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function retunrs an error +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G2Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG2AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG2AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // if infinity is encoded in the metadata, we don't need to read the buffer + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineCompressed, nil + } + if mData == mUncompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + // p.X.A1 | p.X.A0 + p.X.A1.SetBytes(buf[:fp.Bytes]) + p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + // p.Y.A1 | p.Y.A0 + p.Y.A1.SetBytes(buf[fp.Bytes*2 : fp.Bytes*3]) + p.Y.A0.SetBytes(buf[fp.Bytes*3 : fp.Bytes*4]) + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + p.X.A1.SetBytes(bufX[:fp.Bytes]) + p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G2Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y.A0[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + p.X.SetZero() + p.Y.SetZero() + isInfinity = true + return + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + p.X.A1.SetBytes(bufX[:fp.Bytes]) + p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + + // store mData in p.Y.A0[0] + p.Y.A0[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go new file mode 100644 index 0000000000..80fa01be93 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go @@ -0,0 +1,2303 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "errors" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "math" + "runtime" +) + +// selector stores the index, mask and shifts needed to select bits from a scalar +// it is used during the multiExp algorithm or the batch scalar multiplication +type selector struct { + index uint64 // index in the multi-word scalar to select bits from + mask uint64 // mask (c-bit wide) + shift uint64 // shift needed to get our bits on low positions + + multiWordSelect bool // set to true if we need to select bits from 2 words (case where c doesn't divide 64) + maskHigh uint64 // same than mask, for index+1 + shiftHigh uint64 // same than shift, for index+1 +} + +// partitionScalars compute, for each scalars over c-bit wide windows, nbChunk digits +// if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract +// 2^{c} to the current digit, making it negative. +// negative digits can be processed in a later step as adding -G into the bucket instead of G +// (computing -G is cheap, and this saves us half of the buckets in the MultiExp or BatchScalarMul) +// scalarsMont indicates wheter the provided scalars are in montgomery form +// returns smallValues, which represent the number of scalars which meets the following condition +// 0 < scalar < 2^c (in other words, scalars where only the c-least significant bits are non zero) +func partitionScalars(scalars []fr.Element, c uint64, scalarsMont bool, nbTasks int) ([]fr.Element, int) { + toReturn := make([]fr.Element, len(scalars)) + + // number of c-bit radixes in a scalar + nbChunks := fr.Limbs * 64 / c + if (fr.Limbs*64)%c != 0 { + nbChunks++ + } + + mask := uint64((1 << c) - 1) // low c bits are 1 + msbWindow := uint64(1 << (c - 1)) // msb of the c-bit window + max := int(1 << (c - 1)) // max value we want for our digits + cDivides64 := (64 % c) == 0 // if c doesn't divide 64, we may need to select over multiple words + + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := uint64(0); chunk < nbChunks; chunk++ { + jc := uint64(chunk * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = !cDivides64 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d + } + + // for each chunk, we could track the number of non-zeros points we will need to process + // this way, if a chunk has more work to do than others, we can spawn off more go routines + // (at the cost of more buckets allocated) + // a simplified approach is to track the small values where only the first word is set + // if this number represent a significant number of points, then we will split first chunk + // processing in the msm in 2, to ensure all go routines finish at ~same time + // /!\ nbTasks is enough as parallel.Execute is not going to spawn more than nbTasks go routine + // if it does, though, this will deadlocK. + chSmallValues := make(chan int, nbTasks) + + parallel.Execute(len(scalars), func(start, end int) { + smallValues := 0 + for i := start; i < end; i++ { + var carry int + + scalar := scalars[i] + if scalarsMont { + scalar.FromMont() + } + if scalar.IsUint64() { + // everything is 0, no need to process this scalar + if scalar[0] == 0 { + continue + } + // low c-bits are 1 in mask + if scalar[0]&mask == scalar[0] { + smallValues++ + } + } + + // for each chunk in the scalar, compute the current digit, and an eventual carry + for chunk := uint64(0); chunk < nbChunks; chunk++ { + s := selectors[chunk] + + // init with carry if any + digit := carry + carry = 0 + + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + + // if digit is zero, no impact on result + if digit == 0 { + continue + } + + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract + // 2^{c} to the current digit, making it negative. + if digit >= max { + digit -= (1 << c) + carry = 1 + } + + var bits uint64 + if digit >= 0 { + bits = uint64(digit) + } else { + bits = uint64(-digit-1) | msbWindow + } + + toReturn[i][s.index] |= (bits << s.shift) + if s.multiWordSelect { + toReturn[i][s.index+1] |= (bits >> s.shiftHigh) + } + + } + } + + chSmallValues <- smallValues + + }, nbTasks) + + // aggregate small values + close(chSmallValues) + smallValues := 0 + for o := range chSmallValues { + smallValues += o + } + return toReturn, smallValues +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Affine, error) { + var _p G1Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Jac, error) { + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoritical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weigthed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := fr.Limbs * 64 * (nbPoints + (1 << (c))) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + // empirical, needs to be tuned. + // if C > 16 && nbPoints < 1 << 23 { + // C = 16 + // } + return C + } + + var C uint64 + nbSplits := 1 + nbChunks := 0 + for nbChunks < config.NbTasks { + C = bestC(nbPoints) + nbChunks = int(fr.Limbs * 64 / C) // number of c-bit radixes in a scalar + if (fr.Limbs*64)%C != 0 { + nbChunks++ + } + nbChunks *= nbSplits + if nbChunks < config.NbTasks { + nbSplits <<= 1 + nbPoints >>= 1 + } + } + + // partition the scalars + // note: we do that before the actual chunk processing, as for each c-bit window (starting from LSW) + // if it's larger than 2^{c-1}, we have a carry we need to propagate up to the higher window + var smallValues int + scalars, smallValues = partitionScalars(scalars, C, config.ScalarsMont, config.NbTasks) + + // if we have more than 10% of small values, we split the processing of the first chunk in 2 + // we may want to do that in msmInnerG1Jac , but that would incur a cost of looping through all scalars one more time + splitFirstChunk := (float64(smallValues) / float64(len(scalars))) >= 0.1 + + // we have nbSplits intermediate results that we must sum together. + _p := make([]G1Jac, nbSplits-1) + chDone := make(chan int, nbSplits-1) + for i := 0; i < nbSplits-1; i++ { + start := i * nbPoints + end := start + nbPoints + go func(start, end, i int) { + msmInnerG1Jac(&_p[i], int(C), points[start:end], scalars[start:end], splitFirstChunk) + chDone <- i + }(start, end, i) + } + + msmInnerG1Jac(p, int(C), points[(nbSplits-1)*nbPoints:], scalars[(nbSplits-1)*nbPoints:], splitFirstChunk) + for i := 0; i < nbSplits-1; i++ { + done := <-chDone + p.AddAssign(&_p[done]) + } + close(chDone) + return p, nil +} + +func msmInnerG1Jac(p *G1Jac, c int, points []G1Affine, scalars []fr.Element, splitFirstChunk bool) { + + switch c { + + case 4: + p.msmC4(points, scalars, splitFirstChunk) + + case 5: + p.msmC5(points, scalars, splitFirstChunk) + + case 6: + p.msmC6(points, scalars, splitFirstChunk) + + case 7: + p.msmC7(points, scalars, splitFirstChunk) + + case 8: + p.msmC8(points, scalars, splitFirstChunk) + + case 9: + p.msmC9(points, scalars, splitFirstChunk) + + case 10: + p.msmC10(points, scalars, splitFirstChunk) + + case 11: + p.msmC11(points, scalars, splitFirstChunk) + + case 12: + p.msmC12(points, scalars, splitFirstChunk) + + case 13: + p.msmC13(points, scalars, splitFirstChunk) + + case 14: + p.msmC14(points, scalars, splitFirstChunk) + + case 15: + p.msmC15(points, scalars, splitFirstChunk) + + case 16: + p.msmC16(points, scalars, splitFirstChunk) + + case 20: + p.msmC20(points, scalars, splitFirstChunk) + + case 21: + p.msmC21(points, scalars, splitFirstChunk) + + case 22: + p.msmC22(points, scalars, splitFirstChunk) + + default: + panic("not implemented") + } +} + +// msmReduceChunkG1Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG1Affine(p *G1Jac, c int, chChunks []chan g1JacExtended) *G1Jac { + var _p g1JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +func msmProcessChunkG1Affine(chunk uint64, + chRes chan<- g1JacExtended, + buckets []g1JacExtended, + c uint64, + points []G1Affine, + scalars []fr.Element) { + + mask := uint64((1 << c) - 1) // low c bits are 1 + msbWindow := uint64(1 << (c - 1)) + + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + jc := uint64(chunk * c) + s := selector{} + s.index = jc / 64 + s.shift = jc - (s.index * 64) + s.mask = mask << s.shift + s.multiWordSelect = (64%c) != 0 && s.shift > (64-c) && s.index < (fr.Limbs-1) + if s.multiWordSelect { + nbBitsHigh := s.shift - uint64(64-c) + s.maskHigh = (1 << nbBitsHigh) - 1 + s.shiftHigh = (c - nbBitsHigh) + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i := 0; i < len(scalars); i++ { + bits := (scalars[i][s.index] & s.mask) >> s.shift + if s.multiWordSelect { + bits += (scalars[i][s.index+1] & s.maskHigh) << s.shiftHigh + } + + if bits == 0 { + continue + } + + // if msbWindow bit is set, we need to substract + if bits&msbWindow == 0 { + // add + buckets[bits-1].addMixed(&points[i]) + } else { + // sub + buckets[bits & ^msbWindow].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].ZZ.IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + chRes <- total + +} + +func (p *G1Jac) msmC4(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 4 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC5(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 5 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC6(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 6 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC7(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 7 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC8(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 8 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC9(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 9 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC10(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 10 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC11(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 11 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC12(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 12 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC13(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 13 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC14(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 14 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC15(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 15 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC16(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 16 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC20(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 20 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC21(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 21 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +func (p *G1Jac) msmC22(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { + const ( + c = 22 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g1JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G1Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g1JacExtended + msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { + var buckets [1 << (c - 1)]g1JacExtended + msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g1JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG1Affine(p, c, chChunks[:]) +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Affine, error) { + var _p G2Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Jac, error) { + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoritical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weigthed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := fr.Limbs * 64 * (nbPoints + (1 << (c))) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + // empirical, needs to be tuned. + // if C > 16 && nbPoints < 1 << 23 { + // C = 16 + // } + return C + } + + var C uint64 + nbSplits := 1 + nbChunks := 0 + for nbChunks < config.NbTasks { + C = bestC(nbPoints) + nbChunks = int(fr.Limbs * 64 / C) // number of c-bit radixes in a scalar + if (fr.Limbs*64)%C != 0 { + nbChunks++ + } + nbChunks *= nbSplits + if nbChunks < config.NbTasks { + nbSplits <<= 1 + nbPoints >>= 1 + } + } + + // partition the scalars + // note: we do that before the actual chunk processing, as for each c-bit window (starting from LSW) + // if it's larger than 2^{c-1}, we have a carry we need to propagate up to the higher window + var smallValues int + scalars, smallValues = partitionScalars(scalars, C, config.ScalarsMont, config.NbTasks) + + // if we have more than 10% of small values, we split the processing of the first chunk in 2 + // we may want to do that in msmInnerG2Jac , but that would incur a cost of looping through all scalars one more time + splitFirstChunk := (float64(smallValues) / float64(len(scalars))) >= 0.1 + + // we have nbSplits intermediate results that we must sum together. + _p := make([]G2Jac, nbSplits-1) + chDone := make(chan int, nbSplits-1) + for i := 0; i < nbSplits-1; i++ { + start := i * nbPoints + end := start + nbPoints + go func(start, end, i int) { + msmInnerG2Jac(&_p[i], int(C), points[start:end], scalars[start:end], splitFirstChunk) + chDone <- i + }(start, end, i) + } + + msmInnerG2Jac(p, int(C), points[(nbSplits-1)*nbPoints:], scalars[(nbSplits-1)*nbPoints:], splitFirstChunk) + for i := 0; i < nbSplits-1; i++ { + done := <-chDone + p.AddAssign(&_p[done]) + } + close(chDone) + return p, nil +} + +func msmInnerG2Jac(p *G2Jac, c int, points []G2Affine, scalars []fr.Element, splitFirstChunk bool) { + + switch c { + + case 4: + p.msmC4(points, scalars, splitFirstChunk) + + case 5: + p.msmC5(points, scalars, splitFirstChunk) + + case 6: + p.msmC6(points, scalars, splitFirstChunk) + + case 7: + p.msmC7(points, scalars, splitFirstChunk) + + case 8: + p.msmC8(points, scalars, splitFirstChunk) + + case 9: + p.msmC9(points, scalars, splitFirstChunk) + + case 10: + p.msmC10(points, scalars, splitFirstChunk) + + case 11: + p.msmC11(points, scalars, splitFirstChunk) + + case 12: + p.msmC12(points, scalars, splitFirstChunk) + + case 13: + p.msmC13(points, scalars, splitFirstChunk) + + case 14: + p.msmC14(points, scalars, splitFirstChunk) + + case 15: + p.msmC15(points, scalars, splitFirstChunk) + + case 16: + p.msmC16(points, scalars, splitFirstChunk) + + case 20: + p.msmC20(points, scalars, splitFirstChunk) + + case 21: + p.msmC21(points, scalars, splitFirstChunk) + + case 22: + p.msmC22(points, scalars, splitFirstChunk) + + default: + panic("not implemented") + } +} + +// msmReduceChunkG2Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG2Affine(p *G2Jac, c int, chChunks []chan g2JacExtended) *G2Jac { + var _p g2JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +func msmProcessChunkG2Affine(chunk uint64, + chRes chan<- g2JacExtended, + buckets []g2JacExtended, + c uint64, + points []G2Affine, + scalars []fr.Element) { + + mask := uint64((1 << c) - 1) // low c bits are 1 + msbWindow := uint64(1 << (c - 1)) + + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + jc := uint64(chunk * c) + s := selector{} + s.index = jc / 64 + s.shift = jc - (s.index * 64) + s.mask = mask << s.shift + s.multiWordSelect = (64%c) != 0 && s.shift > (64-c) && s.index < (fr.Limbs-1) + if s.multiWordSelect { + nbBitsHigh := s.shift - uint64(64-c) + s.maskHigh = (1 << nbBitsHigh) - 1 + s.shiftHigh = (c - nbBitsHigh) + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i := 0; i < len(scalars); i++ { + bits := (scalars[i][s.index] & s.mask) >> s.shift + if s.multiWordSelect { + bits += (scalars[i][s.index+1] & s.maskHigh) << s.shiftHigh + } + + if bits == 0 { + continue + } + + // if msbWindow bit is set, we need to substract + if bits&msbWindow == 0 { + // add + buckets[bits-1].addMixed(&points[i]) + } else { + // sub + buckets[bits & ^msbWindow].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].ZZ.IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + chRes <- total + +} + +func (p *G2Jac) msmC4(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 4 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC5(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 5 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC6(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 6 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC7(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 7 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC8(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 8 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC9(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 9 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC10(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 10 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC11(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 11 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC12(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 12 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC13(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 13 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC14(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 14 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC15(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 15 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC16(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 16 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC20(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 20 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC21(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 21 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} + +func (p *G2Jac) msmC22(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { + const ( + c = 22 // scalars partitioned into c-bit radixes + nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar + ) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack (for most sizes of c) and this is + // critical for performance + + // each go routine sends its result in chChunks[i] channel + var chChunks [nbChunks + 1]chan g2JacExtended + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // c doesn't divide 256, last window is smaller we can allocate less buckets + const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) + go func(j uint64, points []G2Affine, scalars []fr.Element) { + var buckets [1 << (lastC - 1)]g2JacExtended + msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) + }(uint64(nbChunks), points, scalars) + + processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { + var buckets [1 << (c - 1)]g2JacExtended + msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) + } + + for j := int(nbChunks - 1); j > 0; j-- { + go processChunk(j, points, scalars, chChunks[j]) + } + + if !splitFirstChunk { + go processChunk(0, points, scalars, chChunks[0]) + } else { + chSplit := make(chan g2JacExtended, 2) + split := len(points) / 2 + go processChunk(0, points[:split], scalars[:split], chSplit) + go processChunk(0, points[split:], scalars[split:], chSplit) + go func() { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[0] <- s1 + }() + } + + return msmReduceChunkG2Affine(p, c, chChunks[:]) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go new file mode 100644 index 0000000000..ce66baf3ce --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go @@ -0,0 +1,243 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bls12377 + +import ( + "errors" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +// GT target group of the pairing +type GT = fptower.E12 + +type lineEvaluation struct { + r0 fptower.E2 + r1 fptower.E2 + r2 fptower.E2 +} + +// Pair calculates the reduced pairing for a set of points +func Pair(P []G1Affine, Q []G2Affine) (GT, error) { + f, err := MillerLoop(P, Q) + if err != nil { + return GT{}, err + } + return FinalExponentiation(&f), nil +} + +// PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One +func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { + f, err := Pair(P, Q) + if err != nil { + return false, err + } + var one GT + one.SetOne() + return f.Equal(&one), nil +} + +// FinalExponentiation computes the final expo x**(p**6-1)(p**2+1)(p**4 - p**2 +1)/r +func FinalExponentiation(z *GT, _z ...*GT) GT { + + var result GT + result.Set(z) + + for _, e := range _z { + result.Mul(&result, e) + } + + // https://eprint.iacr.org/2016/130.pdf + var t [3]GT + + // easy part + t[0].Conjugate(&result) + result.Inverse(&result) + t[0].Mul(&t[0], &result) + result.FrobeniusSquare(&t[0]). + Mul(&result, &t[0]) + + // hard part (up to permutation) + // Daiki Hayashida and Kenichiro Hayasaka + // and Tadanori Teruya + // https://eprint.iacr.org/2020/875.pdf + t[0].CyclotomicSquare(&result) + t[1].Expt(&result) + t[2].InverseUnitary(&result) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].Frobenius(&t[1]) + t[1].Mul(&t[1], &t[2]) + result.Mul(&result, &t[0]) + t[0].Expt(&t[1]) + t[2].Expt(&t[0]) + t[0].FrobeniusSquare(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[1].Mul(&t[1], &t[0]) + result.Mul(&result, &t[1]) + + return result +} + +// MillerLoop Miller loop +func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { + // check input size match + n := len(P) + if n == 0 || n != len(Q) { + return GT{}, errors.New("invalid inputs sizes") + } + + // filter infinity points + p := make([]G1Affine, 0, n) + q := make([]G2Affine, 0, n) + + for k := 0; k < n; k++ { + if P[k].IsInfinity() || Q[k].IsInfinity() { + continue + } + p = append(p, P[k]) + q = append(q, Q[k]) + } + + n = len(p) + + // projective points for Q + qProj := make([]g2Proj, n) + for k := 0; k < n; k++ { + qProj[k].FromAffine(&q[k]) + } + + var result GT + result.SetOne() + + var l lineEvaluation + + // i == 62 + for k := 0; k < n; k++ { + qProj[k].DoubleStep(&l) + // line eval + l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1.MulByElement(&l.r1, &p[k].X) + result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + for i := 61; i >= 0; i-- { + result.Square(&result) + + for k := 0; k < n; k++ { + qProj[k].DoubleStep(&l) + // line eval + l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1.MulByElement(&l.r1, &p[k].X) + result.MulBy034(&l.r0, &l.r1, &l.r2) + } + + if loopCounter[i] == 0 { + continue + } + + for k := 0; k < n; k++ { + qProj[k].AddMixedStep(&l, &q[k]) + // line eval + l.r0.MulByElement(&l.r0, &p[k].Y) + l.r1.MulByElement(&l.r1, &p[k].X) + result.MulBy034(&l.r0, &l.r1, &l.r2) + } + } + + return result, nil +} + +// DoubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) { + + // get some Element from our pool + var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A.Mul(&p.x, &p.y) + A.Halve() + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.Mul(&D, &bTwistCurveCoeff) + F.Double(&E). + Add(&F, &E) + G.Add(&B, &F) + G.Halve() + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + EE.Square(&E) + K.Double(&EE). + Add(&K, &EE) + + // X, Y, Z + p.x.Sub(&B, &F). + Mul(&p.x, &A) + p.y.Square(&G). + Sub(&p.y, &K) + p.z.Mul(&B, &H) + + // Line evaluation + evaluations.r0.Neg(&H) + evaluations.r1.Double(&J). + Add(&evaluations.r1, &J) + evaluations.r2.Set(&I) +} + +// AddMixedStep point addition in Mixed Homogenous projective and Affine coordinates +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1.Mul(&a.Y, &p.z) + O.Sub(&p.y, &Y2Z1) + X2Z1.Mul(&a.X, &p.z) + L.Sub(&p.x, &X2Z1) + C.Square(&O) + D.Square(&L) + E.Mul(&L, &D) + F.Mul(&p.z, &C) + G.Mul(&p.x, &D) + t0.Double(&G) + H.Add(&E, &F). + Sub(&H, &t0) + t1.Mul(&p.y, &E) + + // X, Y, Z + p.x.Mul(&L, &H) + p.y.Sub(&G, &H). + Mul(&p.y, &O). + Sub(&p.y, &t1) + p.z.Mul(&E, &p.z) + + t2.Mul(&L, &a.Y) + J.Mul(&a.X, &O). + Sub(&J, &t2) + + // Line evaluation + evaluations.r0.Set(&L) + evaluations.r1.Neg(&O) + evaluations.r2.Set(&J) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go new file mode 100644 index 0000000000..613783cfd4 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go @@ -0,0 +1,126 @@ +/* +Copyright © 2020 ConsenSys + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package ecc provides bls12-381, bls12-377, bn254, bw6-761, bls24-315 and bw6-633 elliptic curves implementation (+pairing). +// +// Also +// +// * Multi exponentiation +// * FFT +// * Polynomial commitment schemes +// * MiMC +// * twisted edwards "companion curves" +// * EdDSA (on the "companion" twisted edwards curves) +package ecc + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +// ID represent a unique ID for a curve +type ID uint16 + +// do not modify the order of this enum +const ( + UNKNOWN ID = iota + BN254 + BLS12_377 + BLS12_381 + BLS24_315 + BW6_761 + BW6_633 +) + +// Implemented return the list of curves fully implemented in gnark-crypto +func Implemented() []ID { + return []ID{BN254, BLS12_377, BLS12_381, BW6_761, BLS24_315} +} + +func (id ID) String() string { + // TODO link with config.XXX.Name ? + switch id { + case BLS12_377: + return "bls12_377" + case BLS12_381: + return "bls12_381" + case BN254: + return "bn254" + case BW6_761: + return "bw6_761" + case BW6_633: + return "bw6_633" + case BLS24_315: + return "bls24_315" + default: + panic("unimplemented ecc ID") + } +} + +// Info returns constants related to a curve +func (id ID) Info() Info { + // note to avoid circular dependency these are hard coded + // values are checked for non regression in code generation + switch id { + case BLS12_377: + return newInfo(&config.BLS12_377) + case BLS12_381: + return newInfo(&config.BLS12_381) + case BN254: + return newInfo(&config.BN254) + case BW6_761: + return newInfo(&config.BW6_761) + case BW6_633: + return newInfo(&config.BW6_633) + case BLS24_315: + return newInfo(&config.BLS24_315) + default: + panic("unimplemented ecc ID") + } +} + +type fieldInfo struct { + Bits int + Bytes int + Modulus func() *big.Int +} + +func newInfo(config *config.Curve) Info { + return Info{ + Fp: fieldInfo{ + Bits: config.Fp.NbBits, + Bytes: config.Fp.NbWords * 8, + Modulus: func() *big.Int { return new(big.Int).Set(config.Fp.ModulusBig) }, + }, + Fr: fieldInfo{ + Bits: config.Fr.NbBits, + Bytes: config.Fr.NbWords * 8, + Modulus: func() *big.Int { return new(big.Int).Set(config.Fr.ModulusBig) }, + }, + } +} + +// Info contains constants related to a curve +type Info struct { + Fp, Fr fieldInfo +} + +// MultiExpConfig enables to set optional configuration attribute to a call to MultiExp +type MultiExpConfig struct { + NbTasks int // go routines to be used in the multiexp. can be larger than num cpus. + ScalarsMont bool // indicates if the scalars are in montgommery form. Default to false. +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md new file mode 100644 index 0000000000..b394e4d728 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md @@ -0,0 +1,14 @@ +## Supported curves + +* BLS12-381 (Zcash) +* BN254 (Ethereum) +* BLS12-377 (ZEXE) +* BW6-761 (EC supporting pairing on BLS12-377 field of definition) +* BLS24-315 +* BW6-633 (EC supporting pairing on BLS24-315 field of definition) + +### Twisted edwards curves + +Each of these curve has a `twistededwards` sub-package with its companion curve. In particular, BLS12-381 comapnion curve is known as [Jubjub](https://z.cash/technology/jubjub/) and BN254's [Baby-Jubjub](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf). + +They are of particular interest as they allow efficient elliptic curve cryptography inside zkSNARK circuits. diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/utils.go b/vendor/github.com/consensys/gnark-crypto/ecc/utils.go new file mode 100644 index 0000000000..aca2d8e3fa --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/utils.go @@ -0,0 +1,268 @@ +package ecc + +import ( + "crypto/sha256" + "errors" + "math/big" + "math/bits" +) + +//------------------------------------------------------- +// Ate loop counter (not used for each curve) + +// NafDecomposition gets the naf decomposition of a big number +func NafDecomposition(a *big.Int, result []int8) int { + + var zero, one, two, three big.Int + + one.SetUint64(1) + two.SetUint64(2) + three.SetUint64(3) + + length := 0 + + // some buffers + var buf, aCopy big.Int + aCopy.Set(a) + + for aCopy.Cmp(&zero) != 0 { + + // if aCopy % 2 == 0 + buf.And(&aCopy, &one) + + // aCopy even + if buf.Cmp(&zero) == 0 { + result[length] = 0 + } else { // aCopy odd + buf.And(&aCopy, &three) + if buf.Cmp(&three) == 0 { + result[length] = -1 + aCopy.Add(&aCopy, &one) + } else { + result[length] = 1 + } + } + aCopy.Rsh(&aCopy, 1) + length++ + } + return length +} + +//------------------------------------------------------- +// GLV utils + +// Lattice represents a Z module spanned by V1, V2. +// det is the associated determinant. +type Lattice struct { + V1, V2 [2]big.Int + Det big.Int +} + +// PrecomputeLattice res such that res.V1, res.V2 +// are short vectors satisfying v11+v12lambda=v21+v22lambda=0[r]. +// cf https://www.iacr.org/archive/crypto2001/21390189.pdf +func PrecomputeLattice(r, lambda *big.Int, res *Lattice) { + + var rst [2][3]big.Int + var tmp [3]big.Int + var quotient, remainder, sqroot, _r, _t big.Int + + rst[0][0].Set(r) + rst[0][1].SetUint64(1) + rst[0][2].SetUint64(0) + + rst[1][0].Set(lambda) + rst[1][1].SetUint64(0) + rst[1][2].SetUint64(1) + + sqroot.Sqrt(r) + + var one big.Int + one.SetUint64(1) + + // r_i+1 = r_i-1 - q_i.r_i + // s_i+1 = s_i-1 - q_i.s_i + // t_i+1 = t_i-1 - q_i.s_i + for rst[1][0].Cmp(&sqroot) >= 1 { + + quotient.Div(&rst[0][0], &rst[1][0]) + remainder.Mod(&rst[0][0], &rst[1][0]) + + tmp[0].Set(&rst[1][0]) + tmp[1].Set(&rst[1][1]) + tmp[2].Set(&rst[1][2]) + + rst[1][0].Set(&remainder) + rst[1][1].Mul(&rst[1][1], "ient).Sub(&rst[0][1], &rst[1][1]) + rst[1][2].Mul(&rst[1][2], "ient).Sub(&rst[0][2], &rst[1][2]) + + rst[0][0].Set(&tmp[0]) + rst[0][1].Set(&tmp[1]) + rst[0][2].Set(&tmp[2]) + } + + quotient.Div(&rst[0][0], &rst[1][0]) + remainder.Mod(&rst[0][0], &rst[1][0]) + _r.Set(&remainder) + _t.Mul(&rst[1][2], "ient).Sub(&rst[0][2], &_t) + + res.V1[0].Set(&rst[1][0]) + res.V1[1].Neg(&rst[1][2]) + + // take the shorter of [rst[0][0], rst[0][2]], [_r, _t] + tmp[1].Mul(&rst[0][2], &rst[0][2]) + tmp[0].Mul(&rst[0][0], &rst[0][0]).Add(&tmp[1], &tmp[0]) + tmp[2].Mul(&_r, &_r) + tmp[1].Mul(&_t, &_t).Add(&tmp[2], &tmp[1]) + if tmp[0].Cmp(&tmp[1]) == 1 { + res.V2[0].Set(&_r) + res.V2[1].Neg(&_t) + } else { + res.V2[0].Set(&rst[0][0]) + res.V2[1].Neg(&rst[0][2]) + } + + // sets determinant + tmp[0].Mul(&res.V1[1], &res.V2[0]) + res.Det.Mul(&res.V1[0], &res.V2[1]).Sub(&res.Det, &tmp[0]) + +} + +// SplitScalar outputs u,v such that u+vlambda=s[r]. +// The method is to view s as (s,0) in ZxZ, and find a close +// vector w of (s,0) in , where l is a sub Z-module of +// ker((a,b)->a+blambda[r]): then (u,v)=w-(s,0), and +// u+vlambda=s[r]. +// cf https://www.iacr.org/archive/crypto2001/21390189.pdf +func SplitScalar(s *big.Int, l *Lattice) [2]big.Int { + + var k1, k2 big.Int + k1.Mul(s, &l.V2[1]) + k2.Mul(s, &l.V1[1]).Neg(&k2) + rounding(&k1, &l.Det, &k1) + rounding(&k2, &l.Det, &k2) + v := getVector(l, &k1, &k2) + v[0].Sub(s, &v[0]) + v[1].Neg(&v[1]) + return v +} + +// sets res to the closest integer from n/d +func rounding(n, d, res *big.Int) { + var dshift, r, one big.Int + one.SetUint64(1) + dshift.Rsh(d, 1) + r.Mod(n, d) + res.Div(n, d) + if r.Cmp(&dshift) == 1 { + res.Add(res, &one) + } +} + +// getVector returns axV1 + bxV2 +func getVector(l *Lattice, a, b *big.Int) [2]big.Int { + var res [2]big.Int + var tmp big.Int + tmp.Mul(b, &l.V2[0]) + res[0].Mul(a, &l.V1[0]).Add(&res[0], &tmp) + tmp.Mul(b, &l.V2[1]) + res[1].Mul(a, &l.V1[1]).Add(&res[1], &tmp) + return res +} + +// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 +// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) +func ExpandMsgXmd(msg, dst []byte, lenInBytes int) ([]byte, error) { + + h := sha256.New() + ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) + if ell > 255 { + return nil, errors.New("invalid lenInBytes") + } + if len(dst) > 255 { + return nil, errors.New("invalid domain size (>255 bytes)") + } + sizeDomain := uint8(len(dst)) + + // Z_pad = I2OSP(0, r_in_bytes) + // l_i_b_str = I2OSP(len_in_bytes, 2) + // DST_prime = I2OSP(len(DST), 1) || DST + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + h.Reset() + if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { + return nil, err + } + if _, err := h.Write(msg); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b0 := h.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.Reset() + if _, err := h.Write(b0); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(1)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 := h.Sum(nil) + + res := make([]byte, lenInBytes) + copy(res[:h.Size()], b1) + + for i := 2; i <= ell; i++ { + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + h.Reset() + strxor := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + strxor[j] = b0[j] ^ b1[j] + } + if _, err := h.Write(strxor); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(i)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 = h.Sum(nil) + copy(res[h.Size()*(i-1):h.Size()*i], b1) + } + return res, nil +} + +// NextPowerOfTwo returns the next power of 2 of n +func NextPowerOfTwo(n uint64) uint64 { + c := bits.OnesCount64(n) + if c == 0 { + return 1 + } + if c == 1 { + return n + } + t := bits.LeadingZeros64(n) + if t == 0 { + panic("next power of 2 overflows uint64") + } + return uint64(1) << (64 - t) +} diff --git a/vendor/github.com/consensys/gnark-crypto/field/field.go b/vendor/github.com/consensys/gnark-crypto/field/field.go new file mode 100644 index 0000000000..0c907e7a61 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/field/field.go @@ -0,0 +1,255 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package field provides Golang code generation for efficient field arithmetic operations. +package field + +import ( + "errors" + "math/big" +) + +var ( + errUnsupportedModulus = errors.New("unsupported modulus. goff only works for prime modulus w/ size > 64bits") + errParseModulus = errors.New("can't parse modulus") +) + +// Field precomputed values used in template for code generation of field element APIs +type Field struct { + PackageName string + ElementName string + ModulusBig *big.Int + Modulus string + ModulusHex string + NbWords int + NbBits int + NbWordsLastIndex int + NbWordsIndexesNoZero []int + NbWordsIndexesFull []int + Q []uint64 + QInverse []uint64 + QMinusOneHalvedP []uint64 // ((q-1) / 2 ) + 1 + ASM bool + RSquare []uint64 + One []uint64 + LegendreExponent string // big.Int to base16 string + NoCarry bool + NoCarrySquare bool // used if NoCarry is set, but some op may overflow in square optimization + SqrtQ3Mod4 bool + SqrtAtkin bool + SqrtTonelliShanks bool + SqrtE uint64 + SqrtS []uint64 + SqrtAtkinExponent string // big.Int to base16 string + SqrtSMinusOneOver2 string // big.Int to base16 string + SqrtQ3Mod4Exponent string // big.Int to base16 string + SqrtG []uint64 // NonResidue ^ SqrtR (montgomery form) + + NonResidue []uint64 // (montgomery form) +} + +// NewField returns a data structure with needed informations to generate apis for field element +// +// See field/generator package +func NewField(packageName, elementName, modulus string) (*Field, error) { + // parse modulus + var bModulus big.Int + if _, ok := bModulus.SetString(modulus, 10); !ok { + return nil, errParseModulus + } + + // field info + F := &Field{ + PackageName: packageName, + ElementName: elementName, + Modulus: modulus, + ModulusHex: bModulus.Text(16), + ModulusBig: new(big.Int).Set(&bModulus), + } + // pre compute field constants + F.NbBits = bModulus.BitLen() + F.NbWords = len(bModulus.Bits()) + if F.NbWords < 2 { + return nil, errUnsupportedModulus + } + + F.NbWordsLastIndex = F.NbWords - 1 + + // set q from big int repr + F.Q = toUint64Slice(&bModulus) + _qHalved := big.NewInt(0) + bOne := new(big.Int).SetUint64(1) + _qHalved.Sub(&bModulus, bOne).Rsh(_qHalved, 1).Add(_qHalved, bOne) + F.QMinusOneHalvedP = toUint64Slice(_qHalved, F.NbWords) + + // setting qInverse + _r := big.NewInt(1) + _r.Lsh(_r, uint(F.NbWords)*64) + _rInv := big.NewInt(1) + _qInv := big.NewInt(0) + extendedEuclideanAlgo(_r, &bModulus, _rInv, _qInv) + _qInv.Mod(_qInv, _r) + F.QInverse = toUint64Slice(_qInv, F.NbWords) + + // rsquare + _rSquare := big.NewInt(2) + exponent := big.NewInt(int64(F.NbWords) * 64 * 2) + _rSquare.Exp(_rSquare, exponent, &bModulus) + F.RSquare = toUint64Slice(_rSquare, F.NbWords) + + var one big.Int + one.SetUint64(1) + one.Lsh(&one, uint(F.NbWords)*64).Mod(&one, &bModulus) + F.One = toUint64Slice(&one, F.NbWords) + + // indexes (template helpers) + F.NbWordsIndexesFull = make([]int, F.NbWords) + F.NbWordsIndexesNoZero = make([]int, F.NbWords-1) + for i := 0; i < F.NbWords; i++ { + F.NbWordsIndexesFull[i] = i + if i > 0 { + F.NbWordsIndexesNoZero[i-1] = i + } + } + + // See https://hackmd.io/@zkteam/modular_multiplication + // if the last word of the modulus is smaller or equal to B, + // we can simplify the montgomery multiplication + const B = (^uint64(0) >> 1) - 1 + F.NoCarry = (F.Q[len(F.Q)-1] <= B) && F.NbWords <= 12 + const BSquare = (^uint64(0) >> 2) + F.NoCarrySquare = F.Q[len(F.Q)-1] <= BSquare + + // Legendre exponent (p-1)/2 + var legendreExponent big.Int + legendreExponent.SetUint64(1) + legendreExponent.Sub(&bModulus, &legendreExponent) + legendreExponent.Rsh(&legendreExponent, 1) + F.LegendreExponent = legendreExponent.Text(16) + + // Sqrt pre computes + var qMod big.Int + qMod.SetUint64(4) + if qMod.Mod(&bModulus, &qMod).Cmp(new(big.Int).SetUint64(3)) == 0 { + // q ≡ 3 (mod 4) + // using z ≡ ± x^((p+1)/4) (mod q) + F.SqrtQ3Mod4 = true + var sqrtExponent big.Int + sqrtExponent.SetUint64(1) + sqrtExponent.Add(&bModulus, &sqrtExponent) + sqrtExponent.Rsh(&sqrtExponent, 2) + F.SqrtQ3Mod4Exponent = sqrtExponent.Text(16) + } else { + // q ≡ 1 (mod 4) + qMod.SetUint64(8) + if qMod.Mod(&bModulus, &qMod).Cmp(new(big.Int).SetUint64(5)) == 0 { + // q ≡ 5 (mod 8) + // use Atkin's algorithm + // see modSqrt5Mod8Prime in math/big/int.go + F.SqrtAtkin = true + e := new(big.Int).Rsh(&bModulus, 3) // e = (q - 5) / 8 + F.SqrtAtkinExponent = e.Text(16) + } else { + // use Tonelli-Shanks + F.SqrtTonelliShanks = true + + // Write q-1 =2^e * s , s odd + var s big.Int + one.SetUint64(1) + s.Sub(&bModulus, &one) + + e := s.TrailingZeroBits() + s.Rsh(&s, e) + F.SqrtE = uint64(e) + F.SqrtS = toUint64Slice(&s) + + // find non residue + var nonResidue big.Int + nonResidue.SetInt64(2) + one.SetUint64(1) + for big.Jacobi(&nonResidue, &bModulus) != -1 { + nonResidue.Add(&nonResidue, &one) + } + + // g = nonresidue ^ s + var g big.Int + g.Exp(&nonResidue, &s, &bModulus) + // store g in montgomery form + g.Lsh(&g, uint(F.NbWords)*64).Mod(&g, &bModulus) + F.SqrtG = toUint64Slice(&g, F.NbWords) + + // store non residue in montgomery form + nonResidue.Lsh(&nonResidue, uint(F.NbWords)*64).Mod(&nonResidue, &bModulus) + F.NonResidue = toUint64Slice(&nonResidue) + + // (s+1) /2 + s.Sub(&s, &one).Rsh(&s, 1) + F.SqrtSMinusOneOver2 = s.Text(16) + } + } + + // note: to simplify output files generated, we generated ASM code only for + // moduli that meet the condition F.NoCarry + // asm code generation for moduli with more than 6 words can be optimized further + F.ASM = F.NoCarry && F.NbWords <= 12 + + return F, nil +} + +func toUint64Slice(b *big.Int, nbWords ...int) (s []uint64) { + if len(nbWords) > 0 && nbWords[0] > len(b.Bits()) { + s = make([]uint64, nbWords[0]) + } else { + s = make([]uint64, len(b.Bits())) + } + + for i, v := range b.Bits() { + s[i] = (uint64)(v) + } + return +} + +// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm +// r > q, modifies rinv and qinv such that rinv.r - qinv.q = 1 +func extendedEuclideanAlgo(r, q, rInv, qInv *big.Int) { + var s1, s2, t1, t2, qi, tmpMuls, riPlusOne, tmpMult, a, b big.Int + t1.SetUint64(1) + rInv.Set(big.NewInt(1)) + qInv.Set(big.NewInt(0)) + a.Set(r) + b.Set(q) + + // r_i+1 = r_i-1 - q_i.r_i + // s_i+1 = s_i-1 - q_i.s_i + // t_i+1 = t_i-1 - q_i.s_i + for b.Sign() > 0 { + qi.Div(&a, &b) + riPlusOne.Mod(&a, &b) + + tmpMuls.Mul(&s1, &qi) + tmpMult.Mul(&t1, &qi) + + s2.Set(&s1) + t2.Set(&t1) + + s1.Sub(rInv, &tmpMuls) + t1.Sub(qInv, &tmpMult) + rInv.Set(&s2) + qInv.Set(&t2) + + a.Set(&b) + b.Set(&riPlusOne) + } + qInv.Neg(qInv) +} diff --git a/vendor/github.com/consensys/gnark-crypto/field/field.md b/vendor/github.com/consensys/gnark-crypto/field/field.md new file mode 100644 index 0000000000..4e9648ceb8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/field/field.md @@ -0,0 +1,48 @@ + +# Usage + +At the root of your repo: +```bash +go get github.com/consensys/gnark-crypto/field +``` + +then in a `main.go` (that can be called using a `go:generate` workflow): + +``` +generator.GenerateFF(packageName, structName, modulus, destinationPath, false) +``` + +The generated type has an API that's similar with `big.Int` + +Example API signature +```go +// Mul z = x * y mod q +func (z *Element) Mul(x, y *Element) *Element +``` + +and can be used like so: + +```go +var a, b Element +a.SetUint64(2) +b.SetString("984896738") + +a.Mul(a, b) + +a.Sub(a, a) + .Add(a, b) + .Inv(a) + +b.Exp(b, 42) +b.Neg(b) +``` + +### Build tags + +Generates optimized assembly for `amd64` target. + +For the `Mul` operation, using `ADX` instructions and `ADOX/ADCX` result in a significant performance gain. + +The "default" target `amd64` checks if the running architecture supports these instruction, and reverts to generic path if not. This check adds a branch and forces the function to reserve some bytes on the frame to store the argument to call `_mulGeneric` . + +This package outputs code that can be compiled with `amd64_adx` flag which omits this check. Will crash if the platform running the binary doesn't support the `ADX` instructions (roughly, before 2016). \ No newline at end of file diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go new file mode 100644 index 0000000000..89c3da10af --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go @@ -0,0 +1,30 @@ +package config + +var BLS12_377 = Curve{ + Name: "bls12-377", + CurvePackage: "bls12377", + EnumID: "BLS12_377", + FrModulus: "8444461749428370424248824938781546531375899335154063827935233455917409239041", + FpModulus: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, +} + +func init() { + BLS12_377.init() + Curves = append(Curves, BLS12_377) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go new file mode 100644 index 0000000000..555ccf7e11 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go @@ -0,0 +1,30 @@ +package config + +var BLS12_381 = Curve{ + Name: "bls12-381", + CurvePackage: "bls12381", + EnumID: "BLS12_381", + FrModulus: "52435875175126190479447740508185965837690552500527637822603658699938581184513", + FpModulus: "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, +} + +func init() { + BLS12_381.init() + Curves = append(Curves, BLS12_381) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go new file mode 100644 index 0000000000..eb3db04904 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go @@ -0,0 +1,30 @@ +package config + +var BLS24_315 = Curve{ + Name: "bls24-315", + CurvePackage: "bls24315", + EnumID: "BLS24_315", + FrModulus: "11502027791375260645628074404575422495959608200132055716665986169834464870401", + FpModulus: "39705142709513438335025689890408969744933502416914749335064285505637884093126342347073617133569", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E4", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, +} + +func init() { + BLS24_315.init() + Curves = append(Curves, BLS24_315) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go new file mode 100644 index 0000000000..6cd6eddcc2 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go @@ -0,0 +1,29 @@ +package config + +var BN254 = Curve{ + Name: "bn254", + CurvePackage: "bn254", + EnumID: "BN254", + FrModulus: "21888242871839275222246405745257275088548364400416034343698204186575808495617", + FpModulus: "21888242871839275222246405745257275088696311157297823662689037894645226208583", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: false, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, +} + +func init() { + BN254.init() + Curves = append(Curves, BN254) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go new file mode 100644 index 0000000000..bc8f6bbfe3 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go @@ -0,0 +1,30 @@ +package config + +var BW6_633 = Curve{ + Name: "bw6-633", + CurvePackage: "bw6633", + EnumID: "BW6_633", + FrModulus: "39705142709513438335025689890408969744933502416914749335064285505637884093126342347073617133569", + FpModulus: "20494478644167774678813387386538961497669590920908778075528754551012016751717791778743535050360001387419576570244406805463255765034468441182772056330021723098661967429339971741066259394985997", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + Projective: true, + }, + G2: Point{ + CoordType: "fp.Element", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + }, +} + +func init() { + BW6_633.init() + Curves = append(Curves, BW6_633) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go new file mode 100644 index 0000000000..0c4898738d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go @@ -0,0 +1,30 @@ +package config + +var BW6_761 = Curve{ + Name: "bw6-761", + CurvePackage: "bw6761", + EnumID: "BW6_761", + FrModulus: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", + FpModulus: "6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + Projective: true, + }, + G2: Point{ + CoordType: "fp.Element", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + }, +} + +func init() { + BW6_761.init() + Curves = append(Curves, BW6_761) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go new file mode 100644 index 0000000000..e64b1a874d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go @@ -0,0 +1,47 @@ +package config + +import ( + "github.com/consensys/gnark-crypto/field" +) + +// Curve describes parameters of the curve useful for the template +type Curve struct { + Name string + CurvePackage string + Package string // current package being generated + EnumID string + FpModulus string + FrModulus string + + Fp *field.Field + Fr *field.Field + FpUnusedBits int + G1 Point + G2 Point +} + +func (conf *Curve) init() { + conf.Fp, _ = field.NewField("fp", "Element", conf.FpModulus) + conf.Fr, _ = field.NewField("fr", "Element", conf.FrModulus) + conf.FpUnusedBits = 64 - (conf.Fp.NbBits % 64) +} + +func (c Curve) Equal(other Curve) bool { + return c.Name == other.Name +} + +type Point struct { + CoordType string + PointName string + GLV bool // scalar mulitplication using GLV + CofactorCleaning bool // flag telling if the Cofactor cleaning is available + CRange []int // multiexp bucket method: generate inner methods (with const arrays) for each c + Projective bool // generate projective coordinates +} + +var Curves []Curve + +func defaultCRange() []int { + // default range for C values in the multiExp + return []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go b/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go new file mode 100644 index 0000000000..803de3c1b1 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go @@ -0,0 +1,44 @@ +package parallel + +import ( + "runtime" + "sync" +) + +// Execute process in parallel the work function +func Execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + } + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9b14585fd7..59ac7b0299 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -11,6 +11,10 @@ cloud.google.com/go/iam ## explicit; go 1.16 cloud.google.com/go/secretmanager/apiv1 cloud.google.com/go/secretmanager/internal +# filippo.io/edwards25519 v1.0.0-rc.1 +## explicit; go 1.17 +filippo.io/edwards25519 +filippo.io/edwards25519/field # github.com/0xPolygon/go-ibft v0.0.0-20220810095021-e43142f8d267 ## explicit; go 1.17 github.com/0xPolygon/go-ibft/core @@ -86,6 +90,10 @@ github.com/btcsuite/btcd/btcec/v2/ecdsa # github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 ## explicit; go 1.17 github.com/btcsuite/btcd/chaincfg/chainhash +# github.com/bwesterb/go-ristretto v1.2.0 +## explicit; go 1.13 +github.com/bwesterb/go-ristretto +github.com/bwesterb/go-ristretto/edwards25519 # github.com/cenkalti/backoff/v3 v3.2.2 ## explicit; go 1.12 github.com/cenkalti/backoff/v3 @@ -98,6 +106,34 @@ github.com/cheekybits/genny github.com/cheekybits/genny/generic github.com/cheekybits/genny/out github.com/cheekybits/genny/parse +# github.com/coinbase/kryptology v1.8.0 +## explicit; go 1.17 +github.com/coinbase/kryptology/internal +github.com/coinbase/kryptology/pkg/core +github.com/coinbase/kryptology/pkg/core/curves +github.com/coinbase/kryptology/pkg/core/curves/native +github.com/coinbase/kryptology/pkg/core/curves/native/bls12381 +github.com/coinbase/kryptology/pkg/core/curves/native/k256 +github.com/coinbase/kryptology/pkg/core/curves/native/k256/fp +github.com/coinbase/kryptology/pkg/core/curves/native/k256/fq +github.com/coinbase/kryptology/pkg/core/curves/native/p256 +github.com/coinbase/kryptology/pkg/core/curves/native/p256/fp +github.com/coinbase/kryptology/pkg/core/curves/native/p256/fq +github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fp +github.com/coinbase/kryptology/pkg/core/curves/native/pasta/fq +github.com/coinbase/kryptology/pkg/sharing +github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig +# github.com/consensys/gnark-crypto v0.5.3 +## explicit; go 1.16 +github.com/consensys/gnark-crypto/ecc +github.com/consensys/gnark-crypto/ecc/bls12-377 +github.com/consensys/gnark-crypto/ecc/bls12-377/fp +github.com/consensys/gnark-crypto/ecc/bls12-377/fr +github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc +github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower +github.com/consensys/gnark-crypto/field +github.com/consensys/gnark-crypto/internal/generator/config +github.com/consensys/gnark-crypto/internal/parallel # github.com/containerd/cgroups v1.0.4 ## explicit; go 1.17 github.com/containerd/cgroups