├── testdata ├── .gitkeep ├── transaction │ └── tx_builder │ │ ├── golden │ │ ├── raw_tx_ent.golden │ │ └── raw_tx_base.golden │ │ └── json │ │ └── raw_tx.json └── protocol │ └── protocol.json ├── examples ├── node │ ├── .env.example │ └── main.go ├── transactions │ └── txbuilder │ │ ├── .env.example │ │ └── main.go ├── address │ ├── simple_decode │ │ └── main.go │ ├── restore │ │ ├── README.md │ │ └── main.go │ └── generate │ │ └── main.go └── README.md ├── node ├── types.go ├── node.go ├── README.md ├── cardano-cli.go └── blockfrost.go ├── shell.nix ├── protocol ├── README.md └── protocol.go ├── Makefile ├── network ├── network.go └── README.md ├── .gitignore ├── fees └── linear.go ├── .github └── workflows │ ├── test.yml │ └── codeql-analysis.yml ├── tx ├── README.md ├── tx_body.go ├── tx_witness_set.go ├── tx_input_output.go ├── tx.go ├── tx_builder.go └── tx_builder_test.go ├── address ├── stake_credential.go ├── README.md ├── reward.go ├── enterprise.go ├── base.go ├── byron.go ├── pointer.go ├── address.go └── address_test.go ├── doc.go ├── go.mod ├── README.md ├── internal └── bech32 │ └── bech32.go ├── crypto ├── crypto.go └── edwards25519 │ └── edwards25519.go ├── bip32 └── bip32.go ├── go.sum └── LICENSE /testdata/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/node/.env.example: -------------------------------------------------------------------------------- 1 | BLOCKFROST_PROJECT_ID=YOUR_KEY_HERE -------------------------------------------------------------------------------- /examples/transactions/txbuilder/.env.example: -------------------------------------------------------------------------------- 1 | BLOCKFROST_PROJECT_ID=YOUR_KEY_HERE -------------------------------------------------------------------------------- /node/types.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | // NetworkTip contains parameters from the tip of the network 4 | type NetworkTip struct { 5 | Slot uint `json:"slot,omitempty"` 6 | Epoch uint `json:"epoch,omitempty"` 7 | Block uint `json:"block,omitempty"` 8 | } 9 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } }: 2 | 3 | with pkgs; 4 | 5 | mkShell { 6 | buildInputs = [ 7 | go 8 | gotools 9 | gopls 10 | go-outline 11 | gocode 12 | gopkgs 13 | gocode-gomod 14 | godef 15 | golint 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /protocol/README.md: -------------------------------------------------------------------------------- 1 | # Protocol 2 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/protocol?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/protocol) 3 | 4 | 5 | Package protocol implements structs for epoch protocol parameters. 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS), Windows_NT) 2 | DEL := del 3 | else 4 | DEL := rm 5 | endif 6 | 7 | all : test 8 | 9 | test : coverage clean 10 | 11 | coverage: 12 | go test ./... -v -cover -coverprofile="coverage.out" 13 | go tool cover -html="coverage.out" 14 | 15 | clean : 16 | $(DEL) coverage.out 17 | go clean 18 | -------------------------------------------------------------------------------- /network/network.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | type NetworkInfo struct { 4 | NetworkId byte 5 | ProtocolMagic uint32 6 | } 7 | 8 | func TestNet() *NetworkInfo { 9 | return &NetworkInfo{ 10 | NetworkId: 0b0000, 11 | ProtocolMagic: 1097911063, 12 | } 13 | } 14 | 15 | func MainNet() *NetworkInfo { 16 | return &NetworkInfo{ 17 | NetworkId: 0b0001, 18 | ProtocolMagic: 764824073, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Environment files 9 | *.env 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Editor Files 21 | .vscode/ 22 | .devcontainer 23 | 24 | # Cardano cbor files 25 | *.cbor 26 | 27 | .test_mnm.txt 28 | .DS_Store -------------------------------------------------------------------------------- /fees/linear.go: -------------------------------------------------------------------------------- 1 | package fees 2 | 3 | // LinearFee contains parameters for the linear fee equation `TxFeeFixed + len_bytes(tx) * TxFeePerByte`. 4 | // These are provided in the protocol parameters 5 | type LinearFee struct { 6 | TxFeePerByte uint 7 | TxFeeFixed uint 8 | } 9 | 10 | // NewLinearFee returns a pointer to a new LinearFee from the provided params 11 | func NewLinearFee(feePerByte uint, fixedFee uint) *LinearFee { 12 | return &LinearFee{ 13 | TxFeePerByte: feePerByte, 14 | TxFeeFixed: fixedFee, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testdata/transaction/tx_builder/golden/raw_tx_ent.golden: -------------------------------------------------------------------------------- 1 | 84a40081825820fcbc18c64cdf133f33dd319c5105dc7c4972f2d646ae276fbd00cf7f39f8c38000018282581d61a597e3dc6a2f0b110c31c42abf0965b9705dd3f291c6091a277b36971a004c4b4082583900d25d4ec5f9e13219b4ea8d5d3c6c849b2b2efbcc0c301cca492837a5f798d9772e70e1857607d45339c32e415f05e7250b5df2d06bebba741a0049bf43021a00028bfd031a034b50f7a10081825820f623f6c21958349e8d3c2c6c7e03eacddefd085f6b26730d50e203b3c36c1ea058403e54c3c618143a1b59324e5e79a054f4bece1dec3a26cf574af31521a2bbd11a72bc17852ff791e196a64ee74f8d8aa90755f5f89869aea9937e772e823ed60ff5f6 -------------------------------------------------------------------------------- /testdata/transaction/tx_builder/golden/raw_tx_base.golden: -------------------------------------------------------------------------------- 1 | 84a40081825820fcbc18c64cdf133f33dd319c5105dc7c4972f2d646ae276fbd00cf7f39f8c38000018282583901a597e3dc6a2f0b110c31c42abf0965b9705dd3f291c6091a277b36970819b5831950cb576926eaf9e74706ae43d251a7bf8906a9e1a140a31a004c4b4082583900d25d4ec5f9e13219b4ea8d5d3c6c849b2b2efbcc0c301cca492837a5f798d9772e70e1857607d45339c32e415f05e7250b5df2d06bebba741a0049ba73021a000290cd031a034b50f7a10081825820f623f6c21958349e8d3c2c6c7e03eacddefd085f6b26730d50e203b3c36c1ea05840004a496fb23d3fa701fb3beed2564396222397041324904f5eec10ffe7b16b923cd0d2fa69c4395603a7870a8046378265216e4a03b5d6efd501a55a3e58b001f5f6 -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | - feat** 9 | - test** 10 | - docs** 11 | - ref** 12 | pull_request: 13 | branches: 14 | - master 15 | - main 16 | - develop 17 | 18 | jobs: 19 | test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Set up Go 25 | uses: actions/setup-go@v2 26 | with: 27 | go-version: 1.17 28 | 29 | - name: Test 30 | run: go clean -testcache && go test ./... -v 31 | -------------------------------------------------------------------------------- /network/README.md: -------------------------------------------------------------------------------- 1 | # Network 2 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/network?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/network) 3 | 4 | Package network implements types/utilities for cardano mainnet and testnet IDs and Protocol Magics 5 | 6 | ## Installation 7 | 8 | ```bash 9 | go get github.com/fivebinaries/go-cardano-serialization/network 10 | ``` 11 | 12 | ## License 13 | 14 | Licensed under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0), see [`LICENSE`](https://github.com/fivebinaries/go-cardano-serialization/blob/master/LICENSE) -------------------------------------------------------------------------------- /tx/README.md: -------------------------------------------------------------------------------- 1 | ## Transactions 2 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/tx?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/tx) 3 | 4 | Package tx implements structs for serialization and deserialization of cardano transaction. It also provides a convenience txBuilder to ease creating transactions, adding inputs/outputs, calculating minimum fee and signing the transaction using a your private key. 5 | 6 | ## Installation 7 | 8 | ```bash 9 | go get github.com/fivebinaries/go-cardano-serialization/tx 10 | ``` 11 | 12 | ## License 13 | 14 | Package tx is licensed under Apache License. -------------------------------------------------------------------------------- /testdata/transaction/tx_builder/json/raw_tx.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourceAddress": "addr_test1qrf96nk9l8snyxd5a2x460rvsjdjkthmesxrq8x2fy5r0f0hnrvhwtnsuxzhvp752vuuxtjptuz7wfgtthedq6lthf6qhf562f", 3 | "receiverAddress": "addr_test1qqq4rw80lxmunx05mss95yz9652ncsj6scxlcch0r8yqht30glrqr64x0week9f7vgrv36wdygeqr4zs3q2dtvu34gcqsavqs8", 4 | "amountLovelace": 5000000, 5 | "changeAddress": "addr_test1qrf96nk9l8snyxd5a2x460rvsjdjkthmesxrq8x2fy5r0f0hnrvhwtnsuxzhvp752vuuxtjptuz7wfgtthedq6lthf6qhf562f", 6 | "slotNo": 55267575, 7 | "utxoIn": { 8 | "txHash": "fcbc18c64cdf133f33dd319c5105dc7c4972f2d646ae276fbd00cf7f39f8c380", 9 | "txIndex": 0, 10 | "amountLovelace": 10000000 11 | } 12 | } -------------------------------------------------------------------------------- /address/stake_credential.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | type StakeCredentialType byte 4 | 5 | const ( 6 | KeyStakeCredentialType StakeCredentialType = iota 7 | ScriptStakeCredentialType 8 | ) 9 | 10 | type StakeCredential struct { 11 | Kind StakeCredentialType `cbor:"0,keyasint,omitempty"` 12 | Payload []byte `cbor:"1,keyasint,omitempty"` 13 | } 14 | 15 | func NewKeyStakeCredential(hash []byte) *StakeCredential { 16 | return &StakeCredential{ 17 | Kind: KeyStakeCredentialType, 18 | Payload: hash, 19 | } 20 | } 21 | 22 | func NewScriptStakeCredential(hash []byte) *StakeCredential { 23 | return &StakeCredential{ 24 | Kind: ScriptStakeCredentialType, 25 | Payload: hash, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package go-cardano-serialization is a serialization/deserialization library by fivebinaries. It currently 3 | supports creating addresses, transactions with metadata, signing transactions and encoding/decoding to CBOR. 4 | Signed transactions can be submitted to cardano blockchain through the blockfrost API. 5 | 6 | Module layout: 7 | 8 | ` 9 | go-cardano-serialization 10 | - address 11 | - protocol 12 | - fees 13 | - tx 14 | ` 15 | 16 | Basic Usage: 17 | ## TODO ## 18 | 19 | Examples can be found at 20 | https://github.com/fivebinaries/go-cardano-serialization/tree/master/example 21 | If you find an issue with the SDK, please report through 22 | https://github.com/fivebinaries/go-cardano-serialization/issues/new 23 | */ 24 | 25 | package gada 26 | -------------------------------------------------------------------------------- /node/node.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "github.com/fivebinaries/go-cardano-serialization/address" 5 | "github.com/fivebinaries/go-cardano-serialization/protocol" 6 | "github.com/fivebinaries/go-cardano-serialization/tx" 7 | ) 8 | 9 | type Node interface { 10 | // UTXOs returns list of unspent transaction outputs 11 | UTXOs(address.Address) ([]tx.TxInput, error) 12 | 13 | // SubmitTx submits a cbor marshalled transaction to the cardano blockchain 14 | // using blockfrost or cardano-cli 15 | SubmitTx(tx.Tx) (string, error) 16 | 17 | // ProtocolParameters returns Protocol Parameters from the network 18 | ProtocolParameters() (protocol.Protocol, error) 19 | 20 | // QueryTip returns the tip of the network for use in tx building 21 | // 22 | // Using `query tip` on cardano-cli requires a synced local node 23 | QueryTip() (NetworkTip, error) 24 | } 25 | -------------------------------------------------------------------------------- /examples/address/simple_decode/main.go: -------------------------------------------------------------------------------- 1 | // A basic example of how to initialize an address from bech32 or base58(byron) 2 | // address string 3 | 4 | package main 5 | 6 | import ( 7 | "log" 8 | 9 | "github.com/fivebinaries/go-cardano-serialization/address" 10 | ) 11 | 12 | func main() { 13 | addr, err := address.NewAddress("addr1vxvfjdcr6nd3y65mkqx5gfvgwjarvkt527h35wq3g7a447chmv4zj") 14 | //addr, err := address.NewAddress("addr_test1qqe92py4mf3ffrtmjuwjpzu6jwlw0zmr50h8ey67qcehlmty5kcrvg2ds9fkpg32t535l9v6lkgaj5cunufgvz5f7snql2fawd") 15 | 16 | if err != nil { 17 | log.Fatal(err) 18 | } 19 | 20 | switch addr.(type) { 21 | case *address.BaseAddress: 22 | log.Println("Base Addr:", addr.String()) 23 | case *address.EnterpriseAddress: 24 | log.Println("Enterprise Address:", addr.String()) 25 | default: 26 | log.Println("Not baseAddress") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testdata/protocol/protocol.json: -------------------------------------------------------------------------------- 1 | { 2 | "txFeePerByte": 44, 3 | "minUTxOValue": 1000000, 4 | "decentralization": 0, 5 | "utxoCostPerWord": null, 6 | "stakePoolDeposit": 500000000, 7 | "poolRetireMaxEpoch": 18, 8 | "extraPraosEntropy": null, 9 | "collateralPercentage": null, 10 | "stakePoolTargetNum": 500, 11 | "maxBlockBodySize": 65536, 12 | "minPoolCost": 340000000, 13 | "maxTxSize": 16384, 14 | "treasuryCut": 0.2, 15 | "maxBlockExecutionUnits": null, 16 | "maxCollateralInputs": null, 17 | "maxValueSize": null, 18 | "maxBlockHeaderSize": 1100, 19 | "maxTxExecutionUnits": null, 20 | "costModels": {}, 21 | "protocolVersion": { 22 | "minor": 0, 23 | "major": 4 24 | }, 25 | "txFeeFixed": 155381, 26 | "stakeAddressDeposit": 2000000, 27 | "monetaryExpansion": 3.0e-3, 28 | "poolPledgeInfluence": 0.3, 29 | "executionUnitPrices": null 30 | } -------------------------------------------------------------------------------- /examples/address/restore/README.md: -------------------------------------------------------------------------------- 1 | # Restore 2 | 3 | This examples demonstrates restoring from 24 word backup keyphrase and creating enterprise and base payment addresses. Addresses can also be created for testnet and mainnet networks. 4 | 5 | 6 | ## Usage 7 | 8 | ```bash 9 | $ go run main.go --help 10 | 11 | Usage of main.exe 12 | -mnemonic string 13 | Mnemonic to restore wallet 14 | -network string 15 | The network ie mainnet or testnet (default "mainnet") 16 | -type uint 17 | Enum of address type(0: Enterprise Address, 1: Base Address) 18 | ``` 19 | 20 | ## Example 21 | 22 | To restore and create base address(payment key + stake key) for testnet from a recovery phrase run 23 | ```bash 24 | go run main.go -mnemonic "24_WORD_BACKUP_PHRASE" -type 1 -network testnet 25 | // addr_test1qqe6zztejhz5hq0xghlf72resflc4t2gmu9xjlf73x8dpf88d78zlt4rng3ccw8g5vvnkyrvt96mug06l5eskxh8rcjq2wyd63 26 | ``` -------------------------------------------------------------------------------- /address/README.md: -------------------------------------------------------------------------------- 1 | # Address 2 | 3 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/address?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/address) 4 | 5 | Package address implements structs for Cardano address types. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | go get github.com/fivebinaries/go-cardano-serialization/address 11 | ``` 12 | 13 | ## Overview 14 | 15 | Address handles serialization and deserilization of addresses used on the Cardano network. Currently supports: 16 | 17 | - Byron/Legacy Address 18 | - Enterprise Address 19 | - Base Address 20 | - Pointer Address 21 | - Reward Address 22 | 23 | Address package also provides an `Address` interface and utility to load address from bech32/base58 encoded strings automatically into one of the supported address types. 24 | 25 | ## Usage 26 | 27 | Examples on how to use the address package can be found in [`examples`](../examples/address/) 28 | 29 | ## License 30 | Package address is licensed under the Apache License -------------------------------------------------------------------------------- /tx/tx_body.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "encoding/hex" 5 | 6 | "github.com/fxamacker/cbor/v2" 7 | ) 8 | 9 | // TxBody contains the inputs, outputs, fee and titme to live for the transaction. 10 | type TxBody struct { 11 | Inputs []*TxInput `cbor:"0,keyasint"` 12 | Outputs []*TxOutput `cbor:"1,keyasint"` 13 | Fee uint64 `cbor:"2,keyasint"` 14 | TTL uint32 `cbor:"3,keyasint,omitempty"` 15 | AuxiliaryDataHash []byte `cbor:"7,keyasint,omitempty"` 16 | } 17 | 18 | // NewTxBody returns a pointer to a new transaction body. 19 | func NewTxBody() *TxBody { 20 | return &TxBody{ 21 | Inputs: make([]*TxInput, 0), 22 | Outputs: make([]*TxOutput, 0), 23 | } 24 | } 25 | 26 | // Bytes returns a slice of cbor Marshalled bytes. 27 | func (b *TxBody) Bytes() ([]byte, error) { 28 | bytes, err := cbor.Marshal(b) 29 | return bytes, err 30 | } 31 | 32 | // Hex returns hex encoded string of the transaction bytes. 33 | func (b *TxBody) Hex() (string, error) { 34 | by, err := b.Bytes() 35 | if err != nil { 36 | return "", err 37 | } 38 | return hex.EncodeToString(by), nil 39 | } 40 | -------------------------------------------------------------------------------- /tx/tx_witness_set.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | type Witness struct { 4 | Keys []*VKeyWitness `cbor:"0,keyasint,omitempty"` 5 | } 6 | 7 | // NewTXWitness returns a pointer to a Witness created from VKeyWitnesses. 8 | func NewTXWitness(keys ...*VKeyWitness) *Witness { 9 | if len(keys) == 0 { 10 | return &Witness{ 11 | Keys: make([]*VKeyWitness, 0), 12 | } 13 | } 14 | 15 | return &Witness{ 16 | Keys: keys, 17 | } 18 | } 19 | 20 | // VKeyWitness - Witness for use with Shelley based transactions 21 | type VKeyWitness struct { 22 | _ struct{} `cbor:",toarray"` 23 | VKey []byte 24 | Signature []byte 25 | } 26 | 27 | // NewVKeyWitness creates a Witness for Shelley Based transactions from a verification key and transaction signature. 28 | func NewVKeyWitness(vkey, signature []byte) *VKeyWitness { 29 | return &VKeyWitness{ 30 | VKey: vkey, Signature: signature, 31 | } 32 | } 33 | 34 | // BootstrapWitness for use with Byron/Legacy based transactions 35 | type BootstrapWitness struct { 36 | _ struct{} `cbor:",toarray"` 37 | VKey []byte 38 | Signature []byte 39 | ChainCode []byte 40 | Attributes []byte 41 | } 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fivebinaries/go-cardano-serialization 2 | 3 | go 1.17 4 | 5 | replace github.com/fivebinaries/go-cardano-serialization => ./ 6 | 7 | require ( 8 | github.com/blockfrost/blockfrost-go v0.1.0 9 | github.com/btcsuite/btcutil v1.0.2 10 | github.com/fxamacker/cbor/v2 v2.4.0 11 | github.com/stretchr/testify v1.7.0 12 | github.com/tyler-smith/go-bip39 v1.1.0 13 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 14 | ) 15 | 16 | require ( 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/fatih/color v1.13.0 // indirect 19 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 20 | github.com/hashicorp/go-hclog v1.0.0 // indirect 21 | github.com/hashicorp/go-retryablehttp v0.7.0 // indirect 22 | github.com/kr/pretty v0.2.0 // indirect 23 | github.com/mattn/go-colorable v0.1.12 // indirect 24 | github.com/mattn/go-isatty v0.0.14 // indirect 25 | github.com/pmezard/go-difflib v1.0.0 // indirect 26 | github.com/x448/float16 v0.8.4 // indirect 27 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect 28 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 29 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /tx/tx_input_output.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "encoding/hex" 5 | 6 | "github.com/fivebinaries/go-cardano-serialization/address" 7 | "github.com/fxamacker/cbor/v2" 8 | ) 9 | 10 | type TxInput struct { 11 | cbor.Marshaler 12 | 13 | TxHash []byte 14 | Index uint16 15 | Amount uint 16 | } 17 | 18 | // NewTxInput creates and returns a *TxInput from Transaction Hash(Hex Encoded), Transaction Index and Amount. 19 | func NewTxInput(txHash string, txIx uint16, amount uint) *TxInput { 20 | hash, _ := hex.DecodeString(txHash) 21 | 22 | return &TxInput{ 23 | TxHash: hash, 24 | Index: txIx, 25 | Amount: amount, 26 | } 27 | } 28 | 29 | func (txI *TxInput) MarshalCBOR() ([]byte, error) { 30 | type arrayInput struct { 31 | _ struct{} `cbor:",toarray"` 32 | TxHash []byte 33 | Index uint16 34 | } 35 | input := arrayInput{ 36 | TxHash: txI.TxHash, 37 | Index: txI.Index, 38 | } 39 | return cbor.Marshal(input) 40 | } 41 | 42 | type TxOutput struct { 43 | _ struct{} `cbor:",toarray"` 44 | Address address.Address 45 | Amount uint 46 | } 47 | 48 | func NewTxOutput(addr address.Address, amount uint) *TxOutput { 49 | return &TxOutput{ 50 | Address: addr, 51 | Amount: amount, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /protocol/protocol.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | ) 7 | 8 | type ProtocolVersion struct { 9 | Major uint8 `json:"major"` 10 | Minor uint8 `json:"minor"` 11 | } 12 | 13 | // Protocol contains protocol parameters. 14 | type Protocol struct { 15 | // The 'a' parameter to calculate the minimum transaction fee in the 16 | // linear equation a * byte_size(tx) + b 17 | TxFeePerByte uint `json:"txFeePerByte"` 18 | 19 | // The 'b' parameter to calculate the minimum transaction fee. 20 | TxFeeFixed uint `json:"txFeeFixed"` 21 | 22 | // The maximum transaction size (in bytes). 23 | MaxTxSize uint `json:"maxTxSize"` 24 | 25 | // The Protocol Version 26 | ProtocolVersion ProtocolVersion `json:"protocolVersion"` 27 | 28 | // Minimum UTXO Value 29 | MinUTXOValue uint `json:"minUTxOValue"` 30 | } 31 | 32 | // LOadProtocol returns a pointer to a unmarshalled Protocol given a file path of a 33 | // protocol parameters file in the cardano-cli generated format. 34 | func LoadProtocol(fp string) (*Protocol, error) { 35 | pByte, err := ioutil.ReadFile(fp) 36 | if err != nil { 37 | return &Protocol{}, err 38 | } 39 | return loadProtocolFromBytes(pByte) 40 | } 41 | 42 | func loadProtocolFromBytes(pByte []byte) (*Protocol, error) { 43 | p := &Protocol{} 44 | 45 | err := json.Unmarshal(pByte, p) 46 | return p, err 47 | } 48 | -------------------------------------------------------------------------------- /examples/address/generate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "log" 6 | 7 | "github.com/fivebinaries/go-cardano-serialization/address" 8 | "github.com/fivebinaries/go-cardano-serialization/bip32" 9 | "github.com/fivebinaries/go-cardano-serialization/network" 10 | "github.com/tyler-smith/go-bip39" 11 | ) 12 | 13 | func harden(num uint) uint32 { 14 | return uint32(0x80000000 + num) 15 | } 16 | 17 | func main() { 18 | entropy, _ := bip39.NewEntropy(256) 19 | mnemonic, _ := bip39.NewMnemonic(entropy) 20 | 21 | log.Println("Mnemonic:", mnemonic) 22 | 23 | rootKey := bip32.FromBip39Entropy( 24 | entropy, 25 | []byte{}, 26 | ) 27 | 28 | accountKey := rootKey.Derive(harden(1852)).Derive(harden(1815)).Derive(harden(0)) 29 | 30 | utxoPubKey := accountKey.Derive(0).Derive(0).Public() 31 | utxoPubKeyHash := utxoPubKey.PublicKey().Hash() 32 | 33 | stakeKey := accountKey.Derive(2).Derive(0).Public() 34 | stakeKeyHash := stakeKey.PublicKey().Hash() 35 | 36 | addr := address.NewBaseAddress( 37 | network.MainNet(), 38 | &address.StakeCredential{ 39 | Kind: address.KeyStakeCredentialType, 40 | Payload: utxoPubKeyHash[:], 41 | }, 42 | &address.StakeCredential{ 43 | Kind: address.KeyStakeCredentialType, 44 | Payload: stakeKeyHash[:], 45 | }) 46 | 47 | log.Println("Address:", addr.String()) 48 | 49 | sign := accountKey.Sign([]byte("Hello There")) 50 | log.Println("Signature:", hex.EncodeToString(sign[:])) 51 | } 52 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | ## Overview 3 | 4 | Folder examples provides examples to get you started on creating addresses, building transactions and submitting transactions to Cardano network(testnet or mainnet). 5 | 6 | ## Installation 7 | ```bash 8 | $ go get github.com/fivebinaries/go-cardano-serialization 9 | ``` 10 | 11 | ## Examples 12 | ### Address 13 | - [Generate Address](./address/generate/) 14 | 15 | Demonstrates generating addresses and exporting mnemonic backup phrases. 16 | 17 | - [Restore Address](./address/restore/) 18 | 19 | 20 | Demonstrates generating from 24 word backup phrases and deriving enterprise or base addresses for payments. 21 | 22 | - [Simple Decode](./address/simple_decode/) 23 | 24 | Demonstrates usage of the NewAddress function provided in package address for decoding bech32/base58 encoded addresses into one of the supported types(enterprise, base, byron, pointer). The Address interface also provides a `String()` method to encode to bech32 or base58(byron). 25 | 26 | ### Node 27 | 28 | Node package provides an interface for interacting with Blockfrost API or cardano-cli. The examples in `node/` demonstrate how to query UTXOs, Tip information, Protocol Parameters. The node interface can also be used to submit signed transactions using either of the backends. 29 | 30 | ### Transactions 31 | - [Build Transaction](./transactions/) 32 | 33 | Demostrates building, signing and submitting transactions to the cardano network. Utlizes packages address and node. 34 | -------------------------------------------------------------------------------- /node/README.md: -------------------------------------------------------------------------------- 1 | # Node 2 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/node?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization/node) 3 | 4 | 5 | Package node provides an interface for cardano backends/nodes. Node implements two backends; blockfrost API and cardano-cli. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | go get github.com/fivebinaries/go-cardano-serialization/node 11 | ``` 12 | 13 | ## Usage 14 | 15 | Basic usage on how to setup a Blockfrost Node on testnet and query for utxos for an address. 16 | 17 | ```golang 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "log" 23 | "github.com/fivebinaries/go-cardano-serialization/node" 24 | ) 25 | 26 | func prettyPrint(v interface{}) string { 27 | bytes, _ := json.MarshalIndent(v, "", " ") 28 | return string(bytes) 29 | } 30 | 31 | func main() { 32 | cli := node.NewBlockfrostClient( 33 | os.Getenv("BLOCKFROST_PROJECT_ID"), 34 | network.TestNet(), 35 | ) 36 | 37 | addr, err := address.NewAddress( 38 | "addr_test1qqe6zztejhz5hq0xghlf72resflc4t2gmu9xjlf73x8dpf88d78zlt4rng3ccw8g5vvnkyrvt96mug06l5eskxh8rcjq2wyd63" 39 | ) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | 44 | utxos, err := cli.UTXOs(addr) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | 49 | prettyPrint(utxos) 50 | } 51 | 52 | ``` 53 | 54 | More examples on node usage can be found in the [`examples`](../examples/node/) 55 | 56 | ## License 57 | 58 | Licensed under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0), see [`LICENSE`](https://github.com/fivebinaries/go-cardano-serialization/blob/master/LICENSE) -------------------------------------------------------------------------------- /examples/node/main.go: -------------------------------------------------------------------------------- 1 | // An example on how to use the `node` wrapper provided to query address UTXOs, 2 | // network tip, protocol parameters and submit transactions to the network. 3 | // 4 | // The node interface currently has two backends; 5 | // - Blockfrost API 6 | // - cardano-cli 7 | // 8 | // Using Blockfrost API requires a `project_id` from blockfrost.io 9 | // cardano-cli backend is not recommended when accepting raw user input 10 | 11 | package main 12 | 13 | import ( 14 | "encoding/json" 15 | "fmt" 16 | "log" 17 | "os" 18 | 19 | "github.com/fivebinaries/go-cardano-serialization/address" 20 | "github.com/fivebinaries/go-cardano-serialization/network" 21 | "github.com/fivebinaries/go-cardano-serialization/node" 22 | ) 23 | 24 | func prettyPrint(v interface{}) string { 25 | bytes, _ := json.MarshalIndent(v, "", " ") 26 | return string(bytes) 27 | } 28 | 29 | func main() { 30 | // Init a new BlockfrostClient with provided project_id on the testnet network. 31 | cli := node.NewBlockfrostClient( 32 | os.Getenv("BLOCKFROST_PROJECT_ID"), 33 | network.TestNet(), 34 | ) 35 | 36 | p, err := cli.ProtocolParameters() 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | fmt.Printf("\nProtocol Parameters: %+v\n\n", prettyPrint(p)) 42 | 43 | tip, err := cli.QueryTip() 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | 48 | fmt.Printf("Tip: %+v\n\n", prettyPrint(tip)) 49 | 50 | addr, err := address.NewAddress( 51 | "addr_test1qqe6zztejhz5hq0xghlf72resflc4t2gmu9xjlf73x8dpf88d78zlt4rng3ccw8g5vvnkyrvt96mug06l5eskxh8rcjq2wyd63", 52 | ) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | utxos, err := cli.UTXOs(addr) 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | 62 | fmt.Printf("UTXOS: %+v\n\n", prettyPrint(utxos)) 63 | } 64 | -------------------------------------------------------------------------------- /address/reward.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "github.com/fivebinaries/go-cardano-serialization/internal/bech32" 5 | "github.com/fivebinaries/go-cardano-serialization/network" 6 | "github.com/fxamacker/cbor/v2" 7 | ) 8 | 9 | // RewardAddress contains content of the reward/staking address. 10 | // Reward account addresses are used to distribute rewards for participating in the proof-of-stake protocol (either directly or via delegation). 11 | type RewardAddress struct { 12 | Network network.NetworkInfo 13 | Stake StakeCredential 14 | } 15 | 16 | // Bytes returns a length 29 byte slice represantation of the Address. 17 | func (r *RewardAddress) Bytes() []byte { 18 | data := make([]byte, 29) 19 | data[0] = 0b1110_0000 | (byte(r.Stake.Kind) << 4) | (byte(r.Network.NetworkId) & 0xf) 20 | copy(data[1:], r.Stake.Payload[:]) 21 | return data 22 | } 23 | 24 | // String returns a bech32 encoded string of the reward address. 25 | func (r *RewardAddress) String() string { 26 | str, _ := bech32.Encode(r.Prefix(), r.Bytes()) 27 | 28 | return str 29 | } 30 | 31 | // MarshalCBOR returns a cbor encoded byte slice of the base address. 32 | func (r *RewardAddress) MarshalCBOR() ([]byte, error) { 33 | return cbor.Marshal(r.Bytes) 34 | } 35 | 36 | // NetworkInfo returns pointer to NetworkInfo{ProtocolMagigic and NetworkId}. 37 | func (r *RewardAddress) NetworkInfo() *network.NetworkInfo { 38 | return &(r.Network) 39 | } 40 | 41 | // Prefix returns the string prefix for the base address. Prefix `stake` for mainnet addresses and `stake_test` for testnet. 42 | func (r *RewardAddress) Prefix() string { 43 | if r.Network.NetworkId == network.TestNet().NetworkId { 44 | return "stake_test" 45 | } 46 | return "stake" 47 | } 48 | 49 | // NewRewardAddress returns a pointer to a new RewardAddress given the network and stake credentials. 50 | func NewRewardAddress(net *network.NetworkInfo, stake *StakeCredential) *RewardAddress { 51 | return &RewardAddress{ 52 | Network: *net, 53 | Stake: *stake, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /address/enterprise.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "github.com/fivebinaries/go-cardano-serialization/internal/bech32" 5 | "github.com/fivebinaries/go-cardano-serialization/network" 6 | "github.com/fxamacker/cbor/v2" 7 | ) 8 | 9 | // EnterpriseAddress contains content for enterprise addresses. 10 | // Enterprise addresses carry no stake rights, so using these addresses means that you are opting out of participation in the proof-of-stake protocol. 11 | type EnterpriseAddress struct { 12 | Network network.NetworkInfo 13 | Payment StakeCredential 14 | } 15 | 16 | // Bytes returns a length 29 byte slice represantation of the Address. 17 | func (e *EnterpriseAddress) Bytes() []byte { 18 | bytes := make([]byte, 29) 19 | bytes[0] = 0b01100000 | (byte(e.Payment.Kind) << 4) | (byte(e.Network.NetworkId) & 0xf) 20 | copy(bytes[1:], e.Payment.Payload[:]) 21 | return bytes 22 | } 23 | 24 | // String returns a bech32 encoded string of the Enterprise Address. 25 | func (e *EnterpriseAddress) String() string { 26 | str, _ := bech32.Encode(e.Prefix(), e.Bytes()) 27 | return str 28 | } 29 | 30 | // NetworkInfo returns NetworkInfo{ProtocolMagigic and NetworkId}. 31 | func (e *EnterpriseAddress) NetworkInfo() *network.NetworkInfo { 32 | return &(e.Network) 33 | } 34 | 35 | // Prefix returns the string prefix for the Enterprise Address. Prefix `addr` for mainnet addresses and `addr_test` for testnet. 36 | func (e *EnterpriseAddress) Prefix() string { 37 | if e.Network.NetworkId == network.TestNet().NetworkId { 38 | return "addr_test" 39 | } 40 | return "addr" 41 | } 42 | 43 | // MarshalCBOR returns a cbor encoded byte slice of the enterprise address. 44 | func (e *EnterpriseAddress) MarshalCBOR() (bytes []byte, err error) { 45 | return cbor.Marshal(e.Bytes()) 46 | } 47 | 48 | // NewEnterpriseAddress returns a pointer to a new Enterprise Address given the network and payment. 49 | func NewEnterpriseAddress(network *network.NetworkInfo, payment *StakeCredential) *EnterpriseAddress { 50 | return &EnterpriseAddress{ 51 | Network: *network, 52 | Payment: *payment, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |
6 |

7 | 8 | # Go Cardano Serialization Library 9 | [![GoDoc](https://godoc.org/github.com/fivebinaries/go-cardano-serialization?status.svg)](https://godoc.org/github.com/fivebinaries/go-cardano-serialization) 10 | 11 | Golang library for serialization and deserialiation of Cardano data structures. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | go get github.com/fivebinaries/go-cardano-serialization 17 | ``` 18 | 19 | ## Usage 20 | ### Creating a simple transaction 21 | 22 | The simplest transaction on Cardano network contains inputs(Unspent Transaction Outputs) and output. 23 | 24 | ```golang 25 | package main 26 | 27 | import ( 28 | "log" 29 | 30 | "github.com/fivebinaries/go-cardano-serialization/address" 31 | "github.com/fivebinaries/go-cardano-serialization/tx" 32 | ) 33 | 34 | func main() { 35 | adaTx := tx.NewTx() 36 | adaTx.AddInput( 37 | tx.NewInput( 38 | "TX_HASH", // Transaction Hash 39 | 0, // Transaction Index 40 | 10000000 // Lovelace value of UTXO 41 | ) 42 | ) 43 | 44 | receiverAddr, err := address.NewAddress("addr1bech32_receiver_address_here") 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | 49 | adaTx.AddOutput( 50 | tx.NewOutput( 51 | receiverAddr, 52 | 5000000 53 | ) 54 | ) 55 | 56 | // Set an estimated transaction cost 57 | adaTx.SetFee(170000) 58 | 59 | // Set the transaction's time to live 60 | adaTx.SetTTL(505050505) 61 | 62 | // Encode example transaction to cbor hex. 63 | fmt.Println(adaTx.Hex()) 64 | } 65 | ``` 66 | 67 | More examples covering building through signing and submission of transactions can be found in the [`examples`](./examples/) folder. 68 | 69 | ## License 70 | 71 | Licensed under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0), see [`LICENSE`](https://github.com/fivebinaries/go-cardano-serialization/blob/master/LICENSE) 72 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: 17 | - main 18 | - master 19 | - staging 20 | pull_request: 21 | # The branches below must be a subset of the branches above 22 | branches: 23 | - main 24 | - master 25 | - staging 26 | schedule: 27 | - cron: '15 15 * * 1' 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | permissions: 34 | actions: read 35 | contents: read 36 | security-events: write 37 | 38 | strategy: 39 | fail-fast: false 40 | matrix: 41 | language: [ 'go' ] 42 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 43 | # Learn more: 44 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 45 | 46 | steps: 47 | - name: Checkout repository 48 | uses: actions/checkout@v2 49 | 50 | # Initializes the CodeQL tools for scanning. 51 | - name: Initialize CodeQL 52 | uses: github/codeql-action/init@v1 53 | with: 54 | languages: ${{ matrix.language }} 55 | # If you wish to specify custom queries, you can do so here or in a config file. 56 | # By default, queries listed here will override any specified in a config file. 57 | # Prefix the list here with "+" to use these queries and those in the config file. 58 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 59 | 60 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 61 | # If this step fails, then you should remove it and run the build manually (see below) 62 | - name: Autobuild 63 | uses: github/codeql-action/autobuild@v1 64 | 65 | # ℹ️ Command-line programs to run using the OS shell. 66 | # 📚 https://git.io/JvXDl 67 | 68 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 69 | # and modify them (or add more) to build your code if your project 70 | # uses a compiled language 71 | 72 | #- run: | 73 | # make bootstrap 74 | # make release 75 | 76 | - name: Perform CodeQL Analysis 77 | uses: github/codeql-action/analyze@v1 78 | -------------------------------------------------------------------------------- /address/base.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "github.com/fivebinaries/go-cardano-serialization/internal/bech32" 5 | "github.com/fivebinaries/go-cardano-serialization/network" 6 | 7 | "github.com/fxamacker/cbor/v2" 8 | ) 9 | 10 | // BaseAddress contains information of the base address. 11 | // A base address directly specifies the staking key that should control the stake for that address but can be used for transactions without registering the staking key in advance. 12 | type BaseAddress struct { 13 | Network network.NetworkInfo 14 | Payment StakeCredential 15 | Stake StakeCredential 16 | } 17 | 18 | // Bytes returns a length 57 byte slice represantation of the Address. 19 | func (b *BaseAddress) Bytes() []byte { 20 | bytes := make([]byte, 57) 21 | bytes[0] = (byte(b.Payment.Kind) << 4) | (byte(b.Stake.Kind) << 5) | (byte(b.Network.NetworkId) & 0xf) 22 | copy(bytes[1:29], b.Payment.Payload[:]) 23 | copy(bytes[29:], b.Stake.Payload[:]) 24 | return bytes 25 | } 26 | 27 | // String returns a bech32 encoded string of the Enterprise Address. 28 | func (b *BaseAddress) String() string { 29 | str, _ := bech32.Encode(b.Prefix(), b.Bytes()) 30 | 31 | return str 32 | } 33 | 34 | // NetworkInfo returns NetworkInfo{ProtocolMagigic and NetworkId}. 35 | func (b *BaseAddress) NetworkInfo() *network.NetworkInfo { 36 | return &(b.Network) 37 | } 38 | 39 | // Prefix returns the string prefix for the base address. Prefix `addr` for mainnet addresses and `addr_test` for testnet. 40 | func (b *BaseAddress) Prefix() string { 41 | if b.Network.NetworkId == network.TestNet().NetworkId { 42 | return "addr_test" 43 | } 44 | return "addr" 45 | } 46 | 47 | // MarshalCBOR returns a cbor encoded byte slice of the base address. 48 | func (b *BaseAddress) MarshalCBOR() ([]byte, error) { 49 | return cbor.Marshal(b.Bytes()) 50 | } 51 | 52 | // ToEnterprise returns the Enterprise Address from the base address. This is equivalent to removing the stake part of the base address. 53 | func (b *BaseAddress) ToEnterprise() (addr *EnterpriseAddress) { 54 | addr = NewEnterpriseAddress( 55 | &b.Network, 56 | &b.Payment, 57 | ) 58 | return 59 | } 60 | 61 | // ToReward returns the RewardAddress from the base address. This is equivalent to removing the payment part of the base address. 62 | func (b *BaseAddress) ToReward() (addr *RewardAddress) { 63 | addr = NewRewardAddress( 64 | &b.Network, 65 | &b.Stake, 66 | ) 67 | return 68 | } 69 | 70 | // NewBaseAddress returns a pointer to a new BaseAddress given the network, payment and stake credentials. 71 | func NewBaseAddress(network *network.NetworkInfo, payment *StakeCredential, stake *StakeCredential) *BaseAddress { 72 | return &BaseAddress{ 73 | Network: *network, 74 | Payment: *payment, 75 | Stake: *stake, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tx/tx.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | 7 | "github.com/fivebinaries/go-cardano-serialization/fees" 8 | "github.com/fxamacker/cbor/v2" 9 | "golang.org/x/crypto/blake2b" 10 | ) 11 | 12 | type Tx struct { 13 | _ struct{} `cbor:",toarray"` 14 | Body *TxBody 15 | Witness *Witness 16 | Valid bool 17 | Metadata interface{} 18 | } 19 | 20 | // NewTx returns a pointer to a new Transaction 21 | func NewTx() *Tx { 22 | return &Tx{ 23 | Body: NewTxBody(), 24 | Witness: NewTXWitness(), 25 | Valid: true, 26 | } 27 | } 28 | 29 | // Bytes returns a slice of cbor marshalled bytes 30 | func (t *Tx) Bytes() ([]byte, error) { 31 | if err := t.CalculateAuxiliaryDataHash(); err != nil { 32 | return nil, err 33 | } 34 | bytes, err := cbor.Marshal(t) 35 | return bytes, err 36 | } 37 | 38 | // Hex returns hex encoding of the transacion bytes 39 | func (t *Tx) Hex() (string, error) { 40 | bytes, err := t.Bytes() 41 | if err != nil { 42 | return "", err 43 | } 44 | return hex.EncodeToString(bytes), nil 45 | } 46 | 47 | // Hash performs a blake2b hash of the transaction body and returns a slice of [32]byte 48 | func (t *Tx) Hash() ([32]byte, error) { 49 | if err := t.CalculateAuxiliaryDataHash(); err != nil { 50 | return [32]byte{}, err 51 | } 52 | txBody, err := cbor.Marshal(t.Body) 53 | if err != nil { 54 | var bt [32]byte 55 | return bt, err 56 | } 57 | 58 | txHash := blake2b.Sum256(txBody) 59 | return txHash, nil 60 | } 61 | 62 | // Fee returns the fee(in lovelaces) required by the transaction from the linear formula 63 | // fee = txFeeFixed + txFeePerByte*tx_len_in_bytes 64 | func (t *Tx) Fee(lfee *fees.LinearFee) (uint, error) { 65 | if err := t.CalculateAuxiliaryDataHash(); err != nil { 66 | return 0, err 67 | } 68 | txCbor, err := cbor.Marshal(t) 69 | if err != nil { 70 | return 0, err 71 | } 72 | txBodyLen := len(txCbor) 73 | fee := lfee.TxFeeFixed + lfee.TxFeePerByte*uint(txBodyLen) 74 | 75 | return fee, nil 76 | } 77 | 78 | // SetFee sets the fee 79 | func (t *Tx) SetFee(fee uint) { 80 | t.Body.Fee = uint64(fee) 81 | } 82 | 83 | func (t *Tx) CalculateAuxiliaryDataHash() error { 84 | if t.Metadata != nil { 85 | mdBytes, err := cbor.Marshal(&t.Metadata) 86 | if err != nil { 87 | return fmt.Errorf("cannot serialize metadata: %w", err) 88 | } 89 | auxHash := blake2b.Sum256(mdBytes) 90 | t.Body.AuxiliaryDataHash = auxHash[:] 91 | } 92 | return nil 93 | } 94 | 95 | // AddInputs adds the inputs to the transaction body 96 | func (t *Tx) AddInputs(inputs ...*TxInput) error { 97 | t.Body.Inputs = append(t.Body.Inputs, inputs...) 98 | 99 | return nil 100 | } 101 | 102 | // AddOutputs adds the outputs to the transaction body 103 | func (t *Tx) AddOutputs(outputs ...*TxOutput) error { 104 | t.Body.Outputs = append(t.Body.Outputs, outputs...) 105 | 106 | return nil 107 | } 108 | -------------------------------------------------------------------------------- /address/byron.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "errors" 5 | "hash/crc32" 6 | 7 | "github.com/btcsuite/btcutil/base58" 8 | "github.com/fivebinaries/go-cardano-serialization/network" 9 | "github.com/fxamacker/cbor/v2" 10 | ) 11 | 12 | var ( 13 | ErrInvalidByronAddress = errors.New("invalid byron address") 14 | ErrInvalidByronChecksum = errors.New("invalid byron checksum") 15 | ) 16 | 17 | type ByronAddressAttributes struct { 18 | Payload []byte `cbor:"1,keyasint,omitempty"` 19 | Network *uint8 `cbor:"2,keyasint,omitempty"` 20 | } 21 | 22 | type ByronAddress struct { 23 | Hash []byte 24 | Attributes ByronAddressAttributes 25 | Tag uint 26 | } 27 | 28 | // Bytes returns byte slice represantation of the Address. 29 | func (b *ByronAddress) Bytes() (bytes []byte) { 30 | bytes, _ = b.MarshalCBOR() 31 | return bytes 32 | } 33 | 34 | // String returns base58 encoded byron address. 35 | func (b *ByronAddress) String() (str string) { 36 | return base58.Encode(b.Bytes()) 37 | } 38 | 39 | // NetworkInfo returns NetworkInfo{ProtocolMagigic and NetworkId}. 40 | func (b *ByronAddress) NetworkInfo() (ni *network.NetworkInfo) { 41 | if b.Attributes.Network == nil { 42 | return network.MainNet() 43 | } 44 | return network.TestNet() 45 | } 46 | 47 | // MarshalCBOR returns a cbor encoded byte slice of the base address. 48 | func (b *ByronAddress) MarshalCBOR() (bytes []byte, err error) { 49 | raw, err := cbor.Marshal([]interface{}{b.Hash, b.Attributes, b.Tag}) 50 | if err != nil { 51 | return nil, err 52 | } 53 | return cbor.Marshal([]interface{}{ 54 | cbor.Tag{Number: 24, Content: raw}, 55 | uint64(crc32.ChecksumIEEE(raw)), 56 | }) 57 | } 58 | 59 | // UnmarshalCBOR deserializes raw byron address, encoded in cbor, into a Byron Address. 60 | func (b *ByronAddress) UnmarshalCBOR(data []byte) error { 61 | type RawAddr struct { 62 | _ struct{} `cbor:",toarray"` 63 | Tag cbor.Tag 64 | Checksum uint32 65 | } 66 | 67 | var rawAddr RawAddr 68 | 69 | if err := cbor.Unmarshal(data, &rawAddr); err != nil { 70 | return err 71 | } 72 | 73 | rawTag, ok := rawAddr.Tag.Content.([]byte) 74 | if !ok || rawAddr.Tag.Number != 24 { 75 | return ErrInvalidByronAddress 76 | } 77 | 78 | cheksum := crc32.ChecksumIEEE(rawTag) 79 | if rawAddr.Checksum != cheksum { 80 | return ErrInvalidByronChecksum 81 | } 82 | 83 | var byron struct { 84 | _ struct{} `cbor:",toarray"` 85 | Hashed []byte 86 | Attrs ByronAddressAttributes 87 | Tag uint 88 | } 89 | 90 | if err := cbor.Unmarshal(rawTag, &byron); err != nil { 91 | return err 92 | } 93 | 94 | if len(byron.Hashed) != 28 || byron.Tag != 0 { 95 | return errors.New("") 96 | } 97 | 98 | *b = ByronAddress{ 99 | Hash: byron.Hashed, 100 | Attributes: byron.Attrs, 101 | Tag: byron.Tag, 102 | } 103 | 104 | return nil 105 | } 106 | 107 | //Pref returns the string prefix for the base address. "" for byron address since it has no prefix. 108 | func (b *ByronAddress) Prefix() string { 109 | return "" 110 | } 111 | -------------------------------------------------------------------------------- /address/pointer.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | 7 | "github.com/btcsuite/btcutil/bech32" 8 | "github.com/fivebinaries/go-cardano-serialization/network" 9 | "github.com/fxamacker/cbor/v2" 10 | ) 11 | 12 | type StakePointer struct { 13 | Slot uint64 14 | TxIndex uint64 15 | CertIndex uint64 16 | } 17 | 18 | // A pointer address indirectly specifies the staking key that should control the stake for the address. 19 | type PointerAddress struct { 20 | Network network.NetworkInfo 21 | Payment StakeCredential 22 | Stake StakePointer 23 | } 24 | 25 | func VariableNatEncode(num uint64) []byte { 26 | var output []byte 27 | output = append(output, byte(num)&0x7F) 28 | num /= 128 29 | for num > 0 { 30 | output = append(output, byte(num)&0x7F|0x80) 31 | num /= 128 32 | } 33 | reverseAny(output) 34 | return output 35 | } 36 | 37 | func VariableNatDecode(raw []byte) (uint64, int, error) { 38 | var output uint64 39 | output = 0 40 | bytes_read := 0 41 | for _, rbyte := range raw { 42 | output = (output << 7) | uint64(rbyte&0x7F) 43 | bytes_read += 1 44 | if (rbyte & 0x80) == 0 { 45 | return output, bytes_read, nil 46 | } 47 | } 48 | return 0, 0, errors.New("unexpected bytes") 49 | } 50 | 51 | func reverseAny(s interface{}) { 52 | n := reflect.ValueOf(s).Len() 53 | swap := reflect.Swapper(s) 54 | for i, j := 0, n-1; i < j; i, j = i+1, j-1 { 55 | swap(i, j) 56 | } 57 | } 58 | 59 | // MarshalCBOR returns a cbor encoded byte slice of the enterprise address. 60 | func (p *PointerAddress) MarshalCBOR() (bytes []byte, err error) { 61 | return cbor.Marshal(p.Bytes()) 62 | } 63 | 64 | // Bytes retuns a byte slice representation of the pointer address. 65 | func (p *PointerAddress) Bytes() (bytes []byte) { 66 | var buf []byte 67 | 68 | header := 0b0100_0000 | (byte(p.Payment.Kind) << 4) | (byte(p.Network.NetworkId) & 0xF) 69 | buf = append(buf, header) 70 | buf = append(buf, p.Payment.Payload...) 71 | buf = append(buf, VariableNatEncode(p.Stake.Slot)...) 72 | buf = append(buf, VariableNatEncode(p.Stake.TxIndex)...) 73 | 74 | return append(buf, VariableNatEncode(p.Stake.CertIndex)...) 75 | } 76 | 77 | // String returns a bech32 encoded string of the Enterprise Address. 78 | func (p *PointerAddress) String() string { 79 | str, _ := bech32.Encode(p.Prefix(), p.Bytes()) 80 | return str 81 | } 82 | 83 | // Prefix returns the string prefix for the base address. Prefix `addr` for mainnet addresses and `addr_test` for testnet. 84 | func (p *PointerAddress) Prefix() string { 85 | if p.Network == *network.TestNet() { 86 | return "addr_test" 87 | } 88 | return "addr" 89 | } 90 | 91 | // NetworkInfo returns NetworkInfo{ProtocolMagigic and NetworkId}. 92 | func (p *PointerAddress) NetworkInfo() *network.NetworkInfo { 93 | return &(p.Network) 94 | } 95 | 96 | // NewPointer returns a pointer to a new StakePointer given slot, transaction index and certificate index. 97 | func NewPointer(slot, txIndex, certIndex uint64) *StakePointer { 98 | return &StakePointer{ 99 | Slot: slot, 100 | TxIndex: txIndex, 101 | CertIndex: certIndex, 102 | } 103 | } 104 | 105 | // NewPointerAddress returns a pointer to a new Pointer address given the network, payment and stake credentials. 106 | func NewPointerAddress(net network.NetworkInfo, payment StakeCredential, stake StakePointer) *PointerAddress { 107 | return &PointerAddress{ 108 | Network: net, 109 | Payment: payment, 110 | Stake: stake, 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /node/cardano-cli.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "os/exec" 10 | "strconv" 11 | "strings" 12 | 13 | "github.com/fivebinaries/go-cardano-serialization/address" 14 | "github.com/fivebinaries/go-cardano-serialization/network" 15 | "github.com/fivebinaries/go-cardano-serialization/protocol" 16 | "github.com/fivebinaries/go-cardano-serialization/tx" 17 | ) 18 | 19 | type cardanoCli struct { 20 | cliPath string 21 | network *network.NetworkInfo 22 | } 23 | 24 | func (cli *cardanoCli) execCommand(args ...string) (data []byte, err error) { 25 | buf := &bytes.Buffer{} 26 | var cmdSuffix string 27 | 28 | if cli.network.NetworkId == 0 { 29 | cmdSuffix = "--mainnet" 30 | } else { 31 | cmdSuffix = fmt.Sprintf("--testnet-magic %d", cli.network.ProtocolMagic) 32 | } 33 | 34 | args = append(args, cmdSuffix) 35 | cmd := exec.Command(cli.cliPath, args...) 36 | cmd.Stdout = buf 37 | cmd.Stderr = os.Stderr 38 | 39 | err = cmd.Run() 40 | 41 | if err != nil { 42 | return 43 | } 44 | 45 | return buf.Bytes(), nil 46 | } 47 | 48 | func (cli *cardanoCli) ProtocolParameters() (p protocol.Protocol, err error) { 49 | data, err := cli.execCommand("query", "protocol-parameters") 50 | 51 | if err := json.Unmarshal(data, &p); err != nil { 52 | return p, err 53 | } 54 | return 55 | } 56 | 57 | func (cli *cardanoCli) UTXOs(addr address.Address) (txIs []tx.TxInput, err error) { 58 | data, err := cli.execCommand("query", "utxos", fmt.Sprintf("--address %s", addr)) 59 | if err != nil { 60 | return 61 | } 62 | 63 | ldata := strings.Split(string(data), "\n") 64 | lenData := len(data) 65 | 66 | if lenData < 3 { 67 | return 68 | } 69 | 70 | for _, it := range ldata[2 : lenData-1] { 71 | sec := strings.Fields(it) 72 | txIx, err := strconv.ParseUint(sec[1], 10, 16) 73 | if err != nil { 74 | return txIs, err 75 | } 76 | 77 | amSec := strings.Fields(sec[2]) 78 | 79 | amount, err := strconv.Atoi(amSec[0]) 80 | if err != nil { 81 | return txIs, err 82 | } 83 | 84 | utxo := *tx.NewTxInput( 85 | sec[0], 86 | uint16(txIx), 87 | uint(amount), 88 | ) 89 | 90 | txIs = append(txIs, utxo) 91 | } 92 | return 93 | } 94 | 95 | func (cli *cardanoCli) QueryTip() (tip NetworkTip, err error) { 96 | data, err := cli.execCommand("query", "tip") 97 | 98 | if err := json.Unmarshal(data, &tip); err != nil { 99 | return tip, err 100 | } 101 | return 102 | } 103 | 104 | func (cli *cardanoCli) SubmitTx(txFinal tx.Tx) (txHash string, err error) { 105 | type sb struct { 106 | TxType string `json:"type"` 107 | Description string `json:"description"` 108 | CborHex string `json:"cborHex"` 109 | } 110 | 111 | txHex, err := txFinal.Hex() 112 | if err != nil { 113 | return 114 | } 115 | 116 | outTx := sb{ 117 | CborHex: txHex, 118 | } 119 | 120 | tmpFile, err := ioutil.TempFile(os.TempDir(), "gada-tx-") 121 | if err != nil { 122 | return 123 | } 124 | 125 | defer os.Remove(tmpFile.Name()) 126 | 127 | data, err := json.MarshalIndent(outTx, "", " ") 128 | if err != nil { 129 | return 130 | } 131 | 132 | if _, err := tmpFile.Write((data)); err != nil { 133 | return txHash, err 134 | } 135 | 136 | cliData, err := cli.execCommand("submit", fmt.Sprintf("--tx-file %s", tmpFile.Name())) 137 | if err != nil { 138 | return 139 | } 140 | 141 | txHash = string(cliData) 142 | 143 | if err := tmpFile.Close(); err != nil { 144 | return txHash, err 145 | } 146 | return 147 | } 148 | 149 | // NewCardanoCliNode returns a wrapper for the cardano-cli with the Node interface 150 | func NewCardanoCliNode(network *network.NetworkInfo, cliPaths ...string) Node { 151 | var cliPath string 152 | 153 | if len(cliPaths) > 0 { 154 | if cliPaths[0] != "" { 155 | cliPath = cliPaths[0] 156 | } 157 | } else { 158 | cliPath = "cardano-cli" 159 | } 160 | return &cardanoCli{ 161 | cliPath: cliPath, 162 | network: network, 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /examples/address/restore/main.go: -------------------------------------------------------------------------------- 1 | // An example showing how to generate base address and enterprise addresses from a 2 | // 24 word mnemonic phrase. 3 | // 4 | // For help of on usage run `go run main.go --help` 5 | // 6 | // Example: To generate an enterprise address run 7 | // `go run main.go -mnemonic "YOUR_24_WORD_PHRASE_HERE" -type 0` 8 | // Alternatively replace type with 1 when using this cli to generate base addresses 9 | 10 | package main 11 | 12 | import ( 13 | "flag" 14 | "fmt" 15 | "log" 16 | "strings" 17 | 18 | "github.com/fivebinaries/go-cardano-serialization/address" 19 | "github.com/fivebinaries/go-cardano-serialization/bip32" 20 | "github.com/fivebinaries/go-cardano-serialization/network" 21 | "github.com/tyler-smith/go-bip39" 22 | ) 23 | 24 | const ( 25 | enterpriseType uint = iota 26 | baseType 27 | ) 28 | 29 | var mnemFlag string 30 | var addrTypeFlag uint 31 | var networkFlag string 32 | 33 | func init() { 34 | 35 | flag.StringVar(&mnemFlag, "mnemonic", "", "Mnemonic to restore wallet") 36 | flag.UintVar(&addrTypeFlag, "type", enterpriseType, "Enum of address type(0: Enterprise Address, 1: Base Address)") 37 | flag.StringVar(&networkFlag, "network", "mainnet", "The network ie mainnet or testnet") 38 | flag.Parse() 39 | 40 | if mnemFlag == "" { 41 | log.Fatal("mnemonic cannot be empty") 42 | } 43 | 44 | if len(strings.Split(mnemFlag, " ")) != 24 { 45 | log.Fatal("mnemonic should be 24 words long") 46 | } 47 | 48 | } 49 | 50 | func harden(num uint) uint32 { 51 | return uint32(0x80000000 + num) 52 | } 53 | 54 | // checkHandleErr - utility 55 | func checkHandleErr(err error) { 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | } 60 | 61 | func generateEnterprise(net *network.NetworkInfo, entropy []byte) (addr *address.EnterpriseAddress, err error) { 62 | rootKey := bip32.FromBip39Entropy( 63 | entropy, 64 | []byte{}, 65 | ) 66 | 67 | accountKey := rootKey.Derive(harden(1852)).Derive(harden(1815)).Derive(harden(0)) 68 | 69 | utxoPubKey := accountKey.Derive(0).Derive(0).Public() 70 | utxoPubKeyHash := utxoPubKey.PublicKey().Hash() 71 | 72 | addr = address.NewEnterpriseAddress( 73 | net, 74 | address.NewKeyStakeCredential(utxoPubKeyHash[:]), 75 | ) 76 | return 77 | } 78 | 79 | func generateBaseAddress(net *network.NetworkInfo, entropy []byte) (addr address.BaseAddress, err error) { 80 | rootKey := bip32.FromBip39Entropy( 81 | entropy, 82 | []byte{}, 83 | ) 84 | 85 | accountKey := rootKey.Derive(harden(1852)).Derive(harden(1815)).Derive(harden(0)) 86 | 87 | utxoPubKey := accountKey.Derive(0).Derive(0).Public() 88 | utxoPubKeyHash := utxoPubKey.PublicKey().Hash() 89 | 90 | stakeKey := accountKey.Derive(2).Derive(0).Public() 91 | stakeKeyHash := stakeKey.PublicKey().Hash() 92 | 93 | addr = *address.NewBaseAddress( 94 | net, 95 | &address.StakeCredential{ 96 | Kind: address.KeyStakeCredentialType, 97 | Payload: utxoPubKeyHash[:], 98 | }, 99 | &address.StakeCredential{ 100 | Kind: address.KeyStakeCredentialType, 101 | Payload: stakeKeyHash[:], 102 | }) 103 | return 104 | } 105 | 106 | func main() { 107 | 108 | networks := make(map[string]*network.NetworkInfo) 109 | 110 | networks["mainnet"] = network.MainNet() 111 | networks["testnet"] = network.TestNet() 112 | 113 | if _, ok := networks[networkFlag]; !ok { 114 | log.Fatalf("Unsupported network type (%s)", networkFlag) 115 | } 116 | net := networks[networkFlag] 117 | 118 | if addrTypeFlag == enterpriseType { 119 | entropy, err := bip39.EntropyFromMnemonic(mnemFlag) 120 | checkHandleErr(err) 121 | 122 | addr, err := generateEnterprise(net, entropy) 123 | checkHandleErr(err) 124 | 125 | fmt.Printf("Enterprise Address: %s", addr.String()) 126 | 127 | } else if addrTypeFlag == baseType { 128 | entropy, err := bip39.EntropyFromMnemonic(mnemFlag) 129 | checkHandleErr(err) 130 | 131 | addr, err := generateBaseAddress(net, entropy) 132 | checkHandleErr(err) 133 | 134 | fmt.Printf("Base Address: %s", addr.String()) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tx/tx_builder.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "github.com/fivebinaries/go-cardano-serialization/address" 5 | "github.com/fivebinaries/go-cardano-serialization/bip32" 6 | "github.com/fivebinaries/go-cardano-serialization/fees" 7 | "github.com/fivebinaries/go-cardano-serialization/protocol" 8 | ) 9 | 10 | // TxBuilder - used to create, validate and sign transactions. 11 | type TxBuilder struct { 12 | tx *Tx 13 | xprvs []bip32.XPrv 14 | protocol protocol.Protocol 15 | } 16 | 17 | // Sign adds a private key to create signature for witness 18 | func (tb *TxBuilder) Sign(xprv bip32.XPrv) { 19 | tb.xprvs = append(tb.xprvs, xprv) 20 | } 21 | 22 | // Build creates hash of transaction, signs the hash using supplied witnesses and adds them to the transaction. 23 | func (tb *TxBuilder) Build() (tx Tx, err error) { 24 | hash, err := tb.tx.Hash() 25 | if err != nil { 26 | return tx, err 27 | } 28 | 29 | txKeys := []*VKeyWitness{} 30 | for _, prv := range tb.xprvs { 31 | publicKey := prv.Public().PublicKey() 32 | signature := prv.Sign(hash[:]) 33 | 34 | txKeys = append(txKeys, NewVKeyWitness(publicKey, signature[:])) 35 | } 36 | 37 | tb.tx.Witness = NewTXWitness( 38 | txKeys..., 39 | ) 40 | 41 | return *tb.tx, nil 42 | } 43 | 44 | // Tx returns a pointer to the transaction 45 | func (tb *TxBuilder) Tx() (tx *Tx) { 46 | return tb.tx 47 | } 48 | 49 | // AddChangeIfNeeded calculates the excess change from UTXO inputs - outputs and adds it to the transaction body. 50 | func (tb *TxBuilder) AddChangeIfNeeded(addr address.Address) { 51 | // change is amount in utxo minus outputs minus fee 52 | tb.tx.SetFee(tb.MinFee()) 53 | totalI, totalO := tb.getTotalInputOutputs() 54 | 55 | change := totalI - totalO - uint(tb.tx.Body.Fee) 56 | tb.tx.AddOutputs( 57 | NewTxOutput( 58 | addr, 59 | change, 60 | ), 61 | ) 62 | } 63 | 64 | // SetTTL sets the time to live for the transaction. 65 | func (tb *TxBuilder) SetTTL(ttl uint32) { 66 | tb.tx.Body.TTL = ttl 67 | } 68 | 69 | func (tb TxBuilder) getTotalInputOutputs() (inputs, outputs uint) { 70 | for _, inp := range tb.tx.Body.Inputs { 71 | inputs += inp.Amount 72 | } 73 | for _, out := range tb.tx.Body.Outputs { 74 | outputs += uint(out.Amount) 75 | } 76 | 77 | return 78 | } 79 | 80 | // MinFee calculates the minimum fee for the provided transaction. 81 | func (tb TxBuilder) MinFee() (fee uint) { 82 | feeTx := Tx{ 83 | Body: &TxBody{ 84 | Inputs: tb.tx.Body.Inputs, 85 | Outputs: tb.tx.Body.Outputs, 86 | Fee: tb.tx.Body.Fee, 87 | TTL: tb.tx.Body.TTL, 88 | }, 89 | Witness: tb.tx.Witness, 90 | Valid: true, 91 | Metadata: tb.tx.Metadata, 92 | } 93 | feeTx.CalculateAuxiliaryDataHash() 94 | if len(feeTx.Witness.Keys) == 0 { 95 | vWitness := NewVKeyWitness( 96 | make([]byte, 32), 97 | make([]byte, 64), 98 | ) 99 | feeTx.Witness.Keys = append(feeTx.Witness.Keys, vWitness) 100 | } 101 | 102 | totalI, totalO := tb.getTotalInputOutputs() 103 | 104 | if totalI != (totalO) { 105 | inner_addr, _ := address.NewAddress("addr_test1qqe6zztejhz5hq0xghlf72resflc4t2gmu9xjlf73x8dpf88d78zlt4rng3ccw8g5vvnkyrvt96mug06l5eskxh8rcjq2wyd63") 106 | 107 | feeTx.Body.Outputs = append(feeTx.Body.Outputs, NewTxOutput(inner_addr, (totalI-totalO-200000))) 108 | 109 | } 110 | lfee := fees.NewLinearFee(tb.protocol.TxFeePerByte, tb.protocol.TxFeeFixed) 111 | // The fee may have increased enough to increase the number of bytes, so do one more pass 112 | fee, _ = feeTx.Fee(lfee) 113 | feeTx.Body.Fee = uint64(fee) 114 | fee, _ = feeTx.Fee(lfee) 115 | 116 | return 117 | } 118 | 119 | // AddInputs adds inputs to the transaction body 120 | func (tb *TxBuilder) AddInputs(inputs ...*TxInput) { 121 | tb.tx.AddInputs(inputs...) 122 | } 123 | 124 | // AddOutputs add outputs to the transaction body 125 | func (tb *TxBuilder) AddOutputs(outputs ...*TxOutput) { 126 | tb.tx.AddOutputs(outputs...) 127 | } 128 | 129 | // NewTxBuilder returns pointer to a new TxBuilder. 130 | func NewTxBuilder(pr protocol.Protocol, xprvs []bip32.XPrv) *TxBuilder { 131 | return &TxBuilder{ 132 | tx: NewTx(), 133 | xprvs: xprvs, 134 | protocol: pr, 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /internal/bech32/bech32.go: -------------------------------------------------------------------------------- 1 | // 2 | // From https://github.com/Bitrue-exchange/libada-go/blob/4a319a1e2371ffcdb6877c4f5a76aec0493b151a/internal/bech32/bech32.go 3 | // 4 | 5 | package bech32 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | ) 11 | 12 | var charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" 13 | 14 | var generator = []uint32{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} 15 | 16 | func polymod(values []byte) uint32 { 17 | chk := uint32(1) 18 | for _, v := range values { 19 | top := chk >> 25 20 | chk = (chk & 0x1ffffff) << 5 21 | chk = chk ^ uint32(v) 22 | for i := 0; i < 5; i++ { 23 | bit := top >> i & 1 24 | if bit == 1 { 25 | chk ^= generator[i] 26 | } 27 | } 28 | } 29 | return chk 30 | } 31 | 32 | func hrpExpand(hrp string) []byte { 33 | h := []byte(strings.ToLower(hrp)) 34 | var ret []byte 35 | for _, c := range h { 36 | ret = append(ret, c>>5) 37 | } 38 | ret = append(ret, 0) 39 | for _, c := range h { 40 | ret = append(ret, c&31) 41 | } 42 | return ret 43 | } 44 | 45 | func verifyChecksum(hrp string, data []byte) bool { 46 | return polymod(append(hrpExpand(hrp), data...)) == 1 47 | } 48 | 49 | func createChecksum(hrp string, data []byte) []byte { 50 | values := append(hrpExpand(hrp), data...) 51 | values = append(values, []byte{0, 0, 0, 0, 0, 0}...) 52 | mod := polymod(values) ^ 1 53 | ret := make([]byte, 6) 54 | for p := range ret { 55 | shift := 5 * (5 - p) 56 | ret[p] = byte(mod>>shift) & 31 57 | } 58 | return ret 59 | } 60 | 61 | func convertBits(data []byte, frombits, tobits byte, pad bool) ([]byte, error) { 62 | var ret []byte 63 | acc := uint32(0) 64 | bits := byte(0) 65 | maxv := byte(1<>frombits != 0 { 68 | return nil, fmt.Errorf("invalid data range: data[%d]=%d (frombits=%d)", idx, value, frombits) 69 | } 70 | acc = acc<= tobits { 73 | bits -= tobits 74 | ret = append(ret, byte(acc>>bits)&maxv) 75 | } 76 | } 77 | if pad { 78 | if bits > 0 { 79 | ret = append(ret, byte(acc<<(tobits-bits))&maxv) 80 | } 81 | } else if bits >= frombits { 82 | return nil, fmt.Errorf("illegal zero padding") 83 | } else if byte(acc<<(tobits-bits))&maxv != 0 { 84 | return nil, fmt.Errorf("non-zero padding") 85 | } 86 | return ret, nil 87 | } 88 | 89 | func Encode(hrp string, data []byte) (string, error) { 90 | values, err := convertBits(data, 8, 5, true) 91 | if err != nil { 92 | return "", err 93 | } 94 | if len(hrp) < 1 { 95 | return "", fmt.Errorf("invalid HRP: %q", hrp) 96 | } 97 | for p, c := range hrp { 98 | if c < 33 || c > 126 { 99 | return "", fmt.Errorf("invalid HRP character: hrp[%d]=%d", p, c) 100 | } 101 | } 102 | if strings.ToUpper(hrp) != hrp && strings.ToLower(hrp) != hrp { 103 | return "", fmt.Errorf("mixed case HRP: %q", hrp) 104 | } 105 | lower := strings.ToLower(hrp) == hrp 106 | hrp = strings.ToLower(hrp) 107 | var ret strings.Builder 108 | ret.WriteString(hrp) 109 | ret.WriteString("1") 110 | for _, p := range values { 111 | ret.WriteByte(charset[p]) 112 | } 113 | for _, p := range createChecksum(hrp, values) { 114 | ret.WriteByte(charset[p]) 115 | } 116 | if lower { 117 | return ret.String(), nil 118 | } 119 | return strings.ToUpper(ret.String()), nil 120 | } 121 | 122 | func Decode(s string) (hrp string, data []byte, err error) { 123 | if strings.ToLower(s) != s && strings.ToUpper(s) != s { 124 | return "", nil, fmt.Errorf("mixed case") 125 | } 126 | pos := strings.LastIndex(s, "1") 127 | if pos < 1 || pos+7 > len(s) { 128 | return "", nil, fmt.Errorf("separator '1' at invalid position: pos=%d, len=%d", pos, len(s)) 129 | } 130 | hrp = s[:pos] 131 | for p, c := range hrp { 132 | if c < 33 || c > 126 { 133 | return "", nil, fmt.Errorf("invalid character human-readable part: s[%d]=%d", p, c) 134 | } 135 | } 136 | s = strings.ToLower(s) 137 | for p, c := range s[pos+1:] { 138 | d := strings.IndexRune(charset, c) 139 | if d == -1 { 140 | return "", nil, fmt.Errorf("invalid character data part: s[%d]=%v", p, c) 141 | } 142 | data = append(data, byte(d)) 143 | } 144 | if !verifyChecksum(hrp, data) { 145 | return "", nil, fmt.Errorf("invalid checksum") 146 | } 147 | data, err = convertBits(data[:len(data)-6], 5, 8, false) 148 | if err != nil { 149 | return "", nil, err 150 | } 151 | return hrp, data, nil 152 | } 153 | -------------------------------------------------------------------------------- /node/blockfrost.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "strconv" 11 | 12 | "github.com/blockfrost/blockfrost-go" 13 | "github.com/fivebinaries/go-cardano-serialization/address" 14 | "github.com/fivebinaries/go-cardano-serialization/network" 15 | "github.com/fivebinaries/go-cardano-serialization/protocol" 16 | "github.com/fivebinaries/go-cardano-serialization/tx" 17 | ) 18 | 19 | type blockfrostNode struct { 20 | network *network.NetworkInfo 21 | client blockfrost.APIClient 22 | projectId string 23 | } 24 | 25 | func (b *blockfrostNode) getNetwork() (serverUrl string) { 26 | if b.network.NetworkId == 0 { 27 | serverUrl = blockfrost.CardanoTestNet 28 | } else { 29 | serverUrl = blockfrost.CardanoMainNet 30 | } 31 | 32 | return 33 | } 34 | 35 | // UTXOs queries the network for Unspent Transaction Outputs belonging to an address. 36 | func (b *blockfrostNode) UTXOs(addr address.Address) (txIs []tx.TxInput, err error) { 37 | utxos, err := b.client.AddressUTXOs( 38 | context.TODO(), 39 | addr.String(), 40 | blockfrost.APIQueryParams{}, 41 | ) 42 | if err != nil { 43 | return 44 | } 45 | 46 | for _, utxo := range utxos { 47 | var amount uint 48 | for _, am := range utxo.Amount { 49 | if am.Unit == "lovelace" { 50 | 51 | amountI, err := strconv.Atoi(am.Quantity) 52 | if err != nil { 53 | return []tx.TxInput{}, err 54 | } 55 | amount = uint(amountI) 56 | } 57 | 58 | } 59 | txIs = append(txIs, *tx.NewTxInput(utxo.TxHash, uint16(utxo.OutputIndex), amount)) 60 | } 61 | 62 | return 63 | } 64 | 65 | // ProtocolParameters queries the protocol parameters of the network. 66 | func (b *blockfrostNode) ProtocolParameters() (p protocol.Protocol, err error) { 67 | params, err := b.client.LatestEpochParameters(context.TODO()) 68 | if err != nil { 69 | return 70 | } 71 | 72 | minU, err := strconv.Atoi(params.MinUtxo) 73 | if err != nil { 74 | return 75 | } 76 | 77 | return protocol.Protocol{ 78 | TxFeePerByte: uint(params.MinFeeA), 79 | TxFeeFixed: uint(params.MinFeeB), 80 | MaxTxSize: uint(params.MaxTxSize), 81 | ProtocolVersion: protocol.ProtocolVersion{ 82 | uint8(params.ProtocolMajorVer), 83 | uint8(params.ProtocolMinorVer), 84 | }, 85 | MinUTXOValue: uint(minU), 86 | }, nil 87 | } 88 | 89 | // SubmitTx submits a signed transaction to the network and returns the transaction hash or error 90 | func (b *blockfrostNode) SubmitTx(txFinal tx.Tx) (txHash string, err error) { 91 | txB, err := txFinal.Bytes() 92 | if err != nil { 93 | return 94 | } 95 | 96 | req, err := http.NewRequestWithContext( 97 | context.TODO(), 98 | http.MethodPost, 99 | fmt.Sprintf("%s/%s", b.getNetwork(), "tx/submit"), 100 | bytes.NewReader(txB), 101 | ) 102 | if err != nil { 103 | return 104 | } 105 | 106 | req.Header.Add("project_id", b.projectId) 107 | req.Header.Add("Content-Type", "application/cbor") 108 | 109 | cli := &http.Client{} 110 | res, err := cli.Do(req) 111 | if err != nil { 112 | return 113 | } 114 | 115 | resb, err := ioutil.ReadAll(res.Body) 116 | if err != nil { 117 | return "", err 118 | } 119 | 120 | if res.StatusCode != 200 { 121 | err = errors.New(string(resb)) 122 | } 123 | 124 | return string(resb), err 125 | } 126 | 127 | // NewBlockfrostClient returns a wrapper for the blockfrost API/SDK with Node interface 128 | func NewBlockfrostClient(projectId string, network *network.NetworkInfo) Node { 129 | var serverUrl string 130 | if network.NetworkId == 0 { 131 | serverUrl = blockfrost.CardanoTestNet 132 | } else { 133 | serverUrl = blockfrost.CardanoMainNet 134 | } 135 | 136 | client := blockfrost.NewAPIClient( 137 | blockfrost.APIClientOptions{ 138 | ProjectID: projectId, 139 | Server: serverUrl, 140 | }, 141 | ) 142 | 143 | return &blockfrostNode{ 144 | network: network, 145 | client: client, 146 | projectId: projectId, 147 | } 148 | 149 | } 150 | 151 | // QueryTip is the equivalent of 152 | // `cardano-cli query tip ${network_parameters}` 153 | // 154 | func (b *blockfrostNode) QueryTip() (nt NetworkTip, err error) { 155 | block, err := b.client.BlockLatest(context.TODO()) 156 | 157 | if err != nil { 158 | return 159 | } 160 | 161 | nt = NetworkTip{ 162 | Slot: uint(block.Slot), 163 | Epoch: uint(block.Epoch), 164 | Block: uint(block.Height), 165 | } 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /address/address.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | "log" 7 | "strings" 8 | 9 | "github.com/btcsuite/btcutil/base58" 10 | "github.com/fivebinaries/go-cardano-serialization/internal/bech32" 11 | "github.com/fivebinaries/go-cardano-serialization/network" 12 | "github.com/fxamacker/cbor/v2" 13 | ) 14 | 15 | var ( 16 | ErrUnsupportedAddress = errors.New("invalid/unsupported address type") 17 | ) 18 | 19 | type Address interface { 20 | cbor.Marshaler 21 | 22 | // Bytes returns raw bytes for use in tx_outputs 23 | Bytes() []byte 24 | 25 | // String returns bech32 encoded human readable string 26 | String() string 27 | 28 | // NetworkInfo returns NetworkInfo with networks network id and protocol magic 29 | NetworkInfo() *network.NetworkInfo 30 | } 31 | 32 | func NewAddress(raw string) (addr Address, err error) { 33 | var data []byte 34 | 35 | if strings.HasPrefix(raw, "addr") || strings.HasPrefix(raw, "stake") { 36 | _, data, err = bech32.Decode(raw) 37 | } else { 38 | data = base58.Decode(raw) 39 | } 40 | 41 | if err != nil { 42 | return 43 | } 44 | 45 | return NewAddressFromBytes(data) 46 | } 47 | 48 | func NewAddressFromHex(hexAddr string) (addr Address, err error) { 49 | data, err := hex.DecodeString(hexAddr) 50 | if err != nil { 51 | return 52 | } 53 | 54 | return NewAddressFromBytes(data) 55 | } 56 | 57 | func NewAddressFromBytes(data []byte) (addr Address, err error) { 58 | header := data[0] 59 | netId := header & 0x0F 60 | 61 | networks := map[byte]network.NetworkInfo{ 62 | byte(1): *network.MainNet(), 63 | byte(0): *network.TestNet(), 64 | } 65 | 66 | switch (header & 0xF0) >> 4 { 67 | // 1000: byron address 68 | case 0b1000: 69 | var byron ByronAddress 70 | 71 | if err := cbor.Unmarshal(data, &byron); err != nil { 72 | log.Println(err) 73 | return &byron, err 74 | } 75 | 76 | return &byron, nil 77 | 78 | // 0000: base address: keyhash28,keyhash28 79 | // 0001: base address: scripthash28,keyhash28 80 | // 0010: base address: keyhash28,scripthash28 81 | // 0011: base address: scripthash28,scripthash28 82 | case 0b0000, 0b0001, 0b0010, 0b0011: 83 | baseAddr := BaseAddress{ 84 | Network: networks[netId], 85 | Payment: *readAddrCred(data, header, 4, 1), 86 | Stake: *readAddrCred(data, header, 5, 1+28), 87 | } 88 | return &baseAddr, nil 89 | 90 | // 0100: pointer address: keyhash28, 3 variable length uint 91 | // 0101: pointer address: scripthash28, 3 variable length uint 92 | case 0b0100, 0b0101: 93 | const ptrAddrMinSize = 1 + 28 + 1 + 1 + 1 94 | if len(data) < ptrAddrMinSize { 95 | return nil, errors.New("cbor not enough error") 96 | } 97 | byteIndex := 1 98 | paymentCred := readAddrCred(data, header, 4, 1) 99 | byteIndex += 28 100 | slot, slot_bytes, err := VariableNatDecode(data[byteIndex:]) 101 | if err != nil { 102 | return nil, err 103 | } 104 | byteIndex += slot_bytes 105 | txIndex, txBytes, err := VariableNatDecode(data[byteIndex:]) 106 | if err != nil { 107 | return nil, err 108 | } 109 | byteIndex += txBytes 110 | certIndex, certBytes, err := VariableNatDecode(data[byteIndex:]) 111 | if err != nil { 112 | return nil, err 113 | } 114 | byteIndex += certBytes 115 | 116 | if byteIndex < len(data) { 117 | return nil, errors.New("cbor trailing data error") 118 | } 119 | 120 | res := NewPointerAddress(networks[netId], *paymentCred, *NewPointer(slot, txIndex, certIndex)) 121 | return res, nil 122 | 123 | // 0110: enterprise address: keyhash28 124 | // 0111: enterprise address: scripthash28 125 | case 0b0110, 0b0111: 126 | // header + keyhash 127 | 128 | const enterpriseAddrSize = 1 + 28 129 | if len(data) < enterpriseAddrSize { 130 | return nil, errors.New("cbor not enough error") 131 | } 132 | if len(data) > enterpriseAddrSize { 133 | return nil, errors.New("cbor trailing data error") 134 | } 135 | netw := networks[netId] 136 | res := NewEnterpriseAddress(&netw, readAddrCred(data, header, 4, 1)) 137 | return res, nil 138 | case 0b1110, 0b1111: 139 | const rewardAddrSize = 1 + 28 140 | if len(data) < rewardAddrSize { 141 | return nil, errors.New("cbor not enough error") 142 | } 143 | if len(data) > rewardAddrSize { 144 | return nil, errors.New("cbor trailing data error") 145 | } 146 | netw := networks[netId] 147 | res := NewRewardAddress(&netw, readAddrCred(data, header, 4, 1)) 148 | return res, nil 149 | 150 | default: 151 | return nil, ErrUnsupportedAddress 152 | } 153 | } 154 | 155 | func readAddrCred(data []byte, header byte, bit byte, pos int) *StakeCredential { 156 | hashBytes := data[pos : pos+28] 157 | 158 | if header&(1<= uint(minRequired) { 137 | firstMatchInput = utxo 138 | } 139 | } 140 | 141 | // Add the transaction Input / UTXO 142 | builder.AddInputs(&firstMatchInput) 143 | 144 | // Add a transaction output with the receiver's address and amount of 5 ADA 145 | builder.AddOutputs(tx.NewTxOutput( 146 | receiver, 147 | uint(sendAmount), 148 | )) 149 | 150 | // Query tip from a node on the network. This is to get the current slot 151 | // and compute TTL of transaction. 152 | tip, err := cli.QueryTip() 153 | if err != nil { 154 | log.Fatal(err) 155 | } 156 | 157 | // Set TTL for 5 min into the future 158 | builder.SetTTL(uint32(tip.Slot) + uint32(300)) 159 | 160 | // Route back the change to the source address 161 | // This is equivalent to adding an output with the source address and change amount 162 | builder.AddChangeIfNeeded(sourceAddr) 163 | 164 | // Build loops through the witness private keys and signs the transaction body hash 165 | txFinal, err := builder.Build() 166 | if err != nil { 167 | log.Fatal(err) 168 | } 169 | 170 | txHash, err := cli.SubmitTx(txFinal) 171 | if err != nil { 172 | log.Fatal(err) 173 | } 174 | 175 | fmt.Println(txHash) 176 | } 177 | -------------------------------------------------------------------------------- /address/address_test.go: -------------------------------------------------------------------------------- 1 | package address_test 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "reflect" 7 | "testing" 8 | 9 | "github.com/fivebinaries/go-cardano-serialization/address" 10 | "github.com/fivebinaries/go-cardano-serialization/network" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | var ( 15 | generate = flag.Bool("gen", false, "generate .golden files") 16 | ) 17 | 18 | func TestAddressInit(t *testing.T) { 19 | type AddressTestCase struct { 20 | description string 21 | address string 22 | addressBytes []byte 23 | addressHex string 24 | err error 25 | network network.NetworkInfo 26 | addrType interface{} 27 | } 28 | addressesScenarios := []AddressTestCase{ 29 | { 30 | description: "valid base address decode and encode", 31 | address: "addr_test1qqe92py4mf3ffrtmjuwjpzu6jwlw0zmr50h8ey67qcehlmty5kcrvg2ds9fkpg32t535l9v6lkgaj5cunufgvz5f7snql2fawd", 32 | addressBytes: []byte{0, 50, 85, 4, 149, 218, 98, 148, 141, 123, 151, 29, 32, 139, 154, 147, 190, 231, 139, 99, 163, 238, 124, 147, 94, 6, 51, 127, 237, 100, 165, 176, 54, 33, 77, 129, 83, 96, 162, 42, 93, 35, 79, 149, 154, 253, 145, 217, 83, 28, 159, 18, 134, 10, 137, 244, 38}, 33 | addressHex: "0032550495da62948d7b971d208b9a93bee78b63a3ee7c935e06337fed64a5b036214d815360a22a5d234f959afd91d9531c9f12860a89f426", 34 | network: *network.TestNet(), 35 | err: nil, 36 | addrType: &address.BaseAddress{}, 37 | }, 38 | { 39 | description: "invalid base address(invalid/missing checksum)", 40 | address: "addr_test1qqe92py4mf3ffrtmjuwjpzu6jwlw0zmr50h8ey67qcehlmty5kcrvg2ds9fkpg32t535l9", 41 | network: *network.TestNet(), 42 | err: errors.New("invalid checksum"), 43 | addrType: nil, 44 | }, 45 | { 46 | description: "valid stake/reward address", 47 | address: "stake1u9w862n8jtje5fuc32l20mqqvwaslpveja6paugnnezz99shxsy55", 48 | addressBytes: []byte{225, 92, 125, 42, 103, 146, 229, 154, 39, 152, 138, 190, 167, 236, 0, 99, 187, 15, 133, 153, 151, 116, 30, 241, 19, 158, 68, 34, 150}, 49 | addressHex: "e15c7d2a6792e59a27988abea7ec0063bb0f859997741ef1139e442296", 50 | network: *network.MainNet(), 51 | err: nil, 52 | addrType: &address.RewardAddress{}, 53 | }, 54 | { 55 | description: "invalid stake/reward address", 56 | address: "stake1u9w862n8jtje5fuc32l20mqqvwaslpveja6paugnnezz99shxsy", 57 | network: *network.MainNet(), 58 | err: errors.New("invalid checksum"), 59 | addrType: nil, 60 | }, 61 | { 62 | description: "valid enterprise address", 63 | address: "addr1vy2qrg3afcprp3lklswy7lux7srcdcd7vghu3md4f0qtd9cszg2k2", 64 | addressBytes: []byte{97, 20, 1, 162, 61, 78, 2, 48, 199, 246, 252, 28, 79, 127, 134, 244, 7, 134, 225, 190, 98, 47, 200, 237, 181, 75, 192, 182, 151}, 65 | addressHex: "611401a23d4e0230c7f6fc1c4f7f86f40786e1be622fc8edb54bc0b697", 66 | network: *network.MainNet(), 67 | err: nil, 68 | addrType: &address.EnterpriseAddress{}, 69 | }, 70 | { 71 | description: "valid yoroi legacy address", 72 | address: "Ae2tdPwUPEZFRbyhz3cpfC2CumGzNkFBN2L42rcUc2yjQpEkxDbkPodpMAi", 73 | addressHex: "82d818582183581cba970ad36654d8dd8f74274b733452ddeab9a62a397746be3c42ccdda0001a9026da5b", 74 | addressBytes: []byte{130, 216, 24, 88, 33, 131, 88, 28, 186, 151, 10, 211, 102, 84, 216, 221, 143, 116, 39, 75, 115, 52, 82, 221, 234, 185, 166, 42, 57, 119, 70, 190, 60, 66, 204, 221, 160, 0, 26, 144, 38, 218, 91}, 75 | network: *network.MainNet(), 76 | err: nil, 77 | addrType: &address.ByronAddress{}, 78 | }, 79 | { 80 | description: "valid deadulus style legacy address", 81 | address: "DdzFFzCqrhsf6zq32tPdqzCqL4JxNSw5aDkiKQp9x8PWUHBXNhR6UNtEeBthFGuf7oSGT2uLKYjoDTyJochABBPCjs6VN4V8eVk7acbe", 82 | addressHex: "82d818584283581c0a1e1b7f0e38e24fbe2e30af04c7c7aab10d838cf2bd24b89e81eb12a101581e581c9b1771bd305e4a6a5a37e8a962ed18fb0a339639e039355feecaa7ff001ab79e49ad", 83 | addressBytes: []byte{130, 216, 24, 88, 66, 131, 88, 28, 10, 30, 27, 127, 14, 56, 226, 79, 190, 46, 48, 175, 4, 199, 199, 170, 177, 13, 131, 140, 242, 189, 36, 184, 158, 129, 235, 18, 161, 1, 88, 30, 88, 28, 155, 23, 113, 189, 48, 94, 74, 106, 90, 55, 232, 169, 98, 237, 24, 251, 10, 51, 150, 57, 224, 57, 53, 95, 238, 202, 167, 255, 0, 26, 183, 158, 73, 173}, 84 | network: *network.MainNet(), 85 | err: nil, 86 | addrType: &address.ByronAddress{}, 87 | }, 88 | } 89 | 90 | checkAddrScenario := func(t *testing.T, scenario AddressTestCase, addr address.Address, err error) { 91 | // TODO: Provide Errors in implementation 92 | if err != nil { 93 | assert.Equal(t, err.Error(), scenario.err.Error()) 94 | } 95 | 96 | if addr != nil { 97 | assert.Equal(t, scenario.address, addr.String()) 98 | assert.Equal(t, scenario.network, *addr.NetworkInfo()) 99 | assert.Equal(t, reflect.TypeOf(addr).String(), reflect.TypeOf(scenario.addrType).String()) 100 | } 101 | } 102 | 103 | for _, scenario := range addressesScenarios { 104 | t.Run(scenario.description, func(t *testing.T) { 105 | 106 | // Default 107 | addr, err := address.NewAddress(scenario.address) 108 | checkAddrScenario(t, scenario, addr, err) 109 | 110 | // Test from bytes 111 | if len(scenario.addressBytes) > 0 { 112 | addr, err := address.NewAddressFromBytes(scenario.addressBytes) 113 | checkAddrScenario(t, scenario, addr, err) 114 | } 115 | 116 | // Test from hex 117 | if scenario.addressHex != "" { 118 | addr, err := address.NewAddressFromHex(scenario.addressHex) 119 | checkAddrScenario(t, scenario, addr, err) 120 | } 121 | }) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /crypto/crypto.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | 7 | "golang.org/x/crypto/blake2b" 8 | ) 9 | 10 | const ( 11 | Ed25519KeyHashLen = 28 12 | ScriptHashLen = 28 13 | TransactionHashLen = 32 14 | GenesisDelegateHashLen = 28 15 | GenesisHashLen = 28 16 | MetadataHashLen = 32 17 | VRFKeyHashLen = 32 18 | BlockHashLen = 32 19 | VRFVKeyLen = 32 20 | KESVKeyLen = 32 21 | PublicKeyLen = 32 22 | Blake2b224Len = 28 23 | Blake2b256Len = 32 24 | ) 25 | 26 | type Ed25519KeyHash [Ed25519KeyHashLen]byte 27 | type ScriptHash [ScriptHashLen]byte 28 | type TransactionHash [TransactionHashLen]byte 29 | type GenesisDelegateHash [GenesisDelegateHashLen]byte 30 | type GenesisHash [GenesisHashLen]byte 31 | type MetadataHash [MetadataHashLen]byte 32 | type VRFKeyHash [VRFKeyHashLen]byte 33 | type BlockHash [BlockHashLen]byte 34 | type VRFVKey [VRFVKeyLen]byte 35 | type KESVKey [KESVKeyLen]byte 36 | 37 | // Blake2b224 implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L15 38 | func Blake2b224(data []byte) [Blake2b224Len]byte { 39 | b2b, err := blake2b.New(Blake2b224Len, nil) 40 | if err != nil { 41 | log.Fatalf("error blake2b224 transform: %s", err) 42 | } 43 | b2b.Write(data) 44 | var result [Blake2b224Len]byte 45 | copy(result[:], b2b.Sum(nil)[:Blake2b224Len]) 46 | return result 47 | } 48 | 49 | // Blake2b256 implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L15 50 | func Blake2b256(data []byte) [Blake2b256Len]byte { 51 | b2b, err := blake2b.New(Blake2b256Len, nil) 52 | if err != nil { 53 | log.Fatalf("error Blake2b256 transform: %s", err) 54 | } 55 | b2b.Write(data) 56 | var result [Blake2b256Len]byte 57 | copy(result[:], b2b.Sum(nil)[:Blake2b256Len]) 58 | return result 59 | } 60 | 61 | // Ed25519KeyHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 62 | func Ed25519KeyHashFromBytes(bytes []byte) (Ed25519KeyHash, error) { 63 | var res Ed25519KeyHash 64 | if len(bytes) != Ed25519KeyHashLen { 65 | return res, errors.New("unexpected bytes") 66 | } 67 | copy(res[:], bytes[:Ed25519KeyHashLen]) 68 | return res, nil 69 | } 70 | 71 | // ScriptHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 72 | func ScriptHashFromBytes(bytes []byte) (ScriptHash, error) { 73 | var res ScriptHash 74 | if len(bytes) != ScriptHashLen { 75 | return res, errors.New("unexpected bytes") 76 | } 77 | copy(res[:], bytes[:ScriptHashLen]) 78 | return res, nil 79 | } 80 | 81 | // TransactionHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 82 | func TransactionHashFromBytes(bytes []byte) (TransactionHash, error) { 83 | var res TransactionHash 84 | if len(bytes) != TransactionHashLen { 85 | return res, errors.New("unexpected bytes") 86 | } 87 | copy(res[:], bytes[:TransactionHashLen]) 88 | return res, nil 89 | } 90 | 91 | // GenesisDelegateHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 92 | func GenesisDelegateHashFromBytes(bytes []byte) (GenesisDelegateHash, error) { 93 | var res GenesisDelegateHash 94 | if len(bytes) != GenesisDelegateHashLen { 95 | return res, errors.New("unexpected bytes") 96 | } 97 | copy(res[:], bytes[:GenesisDelegateHashLen]) 98 | return res, nil 99 | } 100 | 101 | // GenesisHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 102 | func GenesisHashFromBytes(bytes []byte) (GenesisHash, error) { 103 | var res GenesisHash 104 | if len(bytes) != GenesisHashLen { 105 | return res, errors.New("unexpected bytes") 106 | } 107 | copy(res[:], bytes[:GenesisHashLen]) 108 | return res, nil 109 | } 110 | 111 | // MetadataHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 112 | func MetadataHashFromBytes(bytes []byte) (MetadataHash, error) { 113 | var res MetadataHash 114 | if len(bytes) != MetadataHashLen { 115 | return res, errors.New("unexpected bytes") 116 | } 117 | copy(res[:], bytes[:MetadataHashLen]) 118 | return res, nil 119 | } 120 | 121 | // VRFKeyHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 122 | func VRFKeyHashFromBytes(bytes []byte) (VRFKeyHash, error) { 123 | var res VRFKeyHash 124 | if len(bytes) != VRFKeyHashLen { 125 | return res, errors.New("unexpected bytes") 126 | } 127 | copy(res[:], bytes[:VRFKeyHashLen]) 128 | return res, nil 129 | } 130 | 131 | // BlockHashFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 132 | func BlockHashFromBytes(bytes []byte) (BlockHash, error) { 133 | var res BlockHash 134 | if len(bytes) != BlockHashLen { 135 | return res, errors.New("unexpected bytes") 136 | } 137 | copy(res[:], bytes[:BlockHashLen]) 138 | return res, nil 139 | } 140 | 141 | // VRFVKeyFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 142 | func VRFVKeyFromBytes(bytes []byte) (VRFVKey, error) { 143 | var res VRFVKey 144 | if len(bytes) != VRFVKeyLen { 145 | return res, errors.New("unexpected bytes") 146 | } 147 | copy(res[:], bytes[:VRFVKeyLen]) 148 | return res, nil 149 | } 150 | 151 | // KESVKeyFromBytes implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L700 152 | func KESVKeyFromBytes(bytes []byte) (KESVKey, error) { 153 | var res KESVKey 154 | if len(bytes) != KESVKeyLen { 155 | return res, errors.New("unexpected bytes") 156 | } 157 | copy(res[:], bytes[:KESVKeyLen]) 158 | return res, nil 159 | } 160 | -------------------------------------------------------------------------------- /tx/tx_builder_test.go: -------------------------------------------------------------------------------- 1 | package tx_test 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "flag" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "path/filepath" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | 15 | "github.com/fivebinaries/go-cardano-serialization/address" 16 | "github.com/fivebinaries/go-cardano-serialization/bip32" 17 | "github.com/fivebinaries/go-cardano-serialization/network" 18 | "github.com/fivebinaries/go-cardano-serialization/protocol" 19 | "github.com/fivebinaries/go-cardano-serialization/tx" 20 | "github.com/stretchr/testify/assert" 21 | ) 22 | 23 | var ( 24 | _, b, _, _ = runtime.Caller(0) 25 | packagepath = filepath.Dir(b) 26 | ) 27 | 28 | var ( 29 | // update = flag.Bool("update", false, "update .golden files") 30 | generate = flag.Bool("gen", false, "generate .golden files") 31 | ) 32 | 33 | type utxoIn struct { 34 | TxHash string `json:"txHash"` 35 | TxIndex uint `json:"txIndex"` 36 | AmountLovelace uint `json:"amountLovelace"` 37 | } 38 | 39 | type txDetails struct { 40 | ReceiverAddress string `json:"receiverAddress"` 41 | AmountLovelace uint `json:"amountLovelace"` 42 | ChangeAddress string `json:"changeAddress"` 43 | SlotNo uint `json:"slotNo"` 44 | UtxoIn utxoIn `json:"utxoIn"` 45 | } 46 | 47 | type txScenario struct { 48 | Description string 49 | GoldenFile string 50 | AddrProc func(*address.BaseAddress) address.Address 51 | } 52 | 53 | func createRootKey() bip32.XPrv { 54 | rootKey := bip32.FromBip39Entropy( 55 | []byte{214, 64, 138, 69, 145, 210, 32, 51, 202, 45, 90, 151, 33, 194, 153, 176, 188, 94, 94, 186, 67, 118, 194, 227, 207, 157, 54, 49, 34, 12, 83, 93}, 56 | []byte{}, 57 | ) 58 | return rootKey 59 | } 60 | 61 | func harden(num uint) uint32 { 62 | return uint32(0x80000000 + num) 63 | } 64 | 65 | func generateBaseAddress(net *network.NetworkInfo) (addr *address.BaseAddress, utxoPrvKey bip32.XPrv, err error) { 66 | rootKey := createRootKey() 67 | accountKey := rootKey.Derive(harden(1852)).Derive(harden(1815)).Derive(harden(0)) 68 | 69 | utxoPrvKey = accountKey.Derive(0).Derive(0) 70 | utxoPubKey := utxoPrvKey.Public() 71 | utxoPubKeyHash := utxoPubKey.PublicKey().Hash() 72 | 73 | stakeKey := accountKey.Derive(2).Derive(0).Public() 74 | stakeKeyHash := stakeKey.PublicKey().Hash() 75 | 76 | addr = address.NewBaseAddress( 77 | net, 78 | &address.StakeCredential{ 79 | Kind: address.KeyStakeCredentialType, 80 | Payload: utxoPubKeyHash[:], 81 | }, 82 | &address.StakeCredential{ 83 | Kind: address.KeyStakeCredentialType, 84 | Payload: stakeKeyHash[:], 85 | }) 86 | return 87 | } 88 | 89 | func getTxDetails(fp string) (txD txDetails) { 90 | data, err := readJson(fp) 91 | if err != nil { 92 | log.Fatal(err) 93 | } 94 | 95 | if err := json.Unmarshal(data, &txD); err != nil { 96 | log.Fatal("Err", err) 97 | } 98 | 99 | return 100 | 101 | } 102 | 103 | func readJson(fp string) (data []byte, err error) { 104 | file, err := os.Open(fp) 105 | if err != nil { 106 | return 107 | } 108 | 109 | defer file.Close() 110 | 111 | data, err = ioutil.ReadAll(file) 112 | if err != nil { 113 | return 114 | } 115 | 116 | return 117 | } 118 | 119 | func TestTxBuilderRaw(t *testing.T) { 120 | createRootKey() 121 | 122 | packagepath = strings.Replace(packagepath, "\\", "/", -1) 123 | basepath := packagepath[:strings.LastIndex(packagepath, "/")] 124 | 125 | pr, err := protocol.LoadProtocol(filepath.Join(basepath, "testdata", "protocol", "protocol.json")) 126 | if err != nil { 127 | log.Fatal(err) 128 | } 129 | 130 | txD := getTxDetails(filepath.Join(basepath, "testdata", "transaction", "tx_builder", "json", "raw_tx.json")) 131 | 132 | txScenarios := []txScenario{ 133 | { 134 | Description: "Transaction with base address marshalling", 135 | GoldenFile: "raw_tx_base.golden", 136 | AddrProc: func(addr *address.BaseAddress) address.Address { return addr }, 137 | }, 138 | { 139 | Description: "Transaction with enterprise address marshalling", 140 | GoldenFile: "raw_tx_ent.golden", 141 | AddrProc: func(addr *address.BaseAddress) address.Address { return addr.ToEnterprise() }, 142 | }, 143 | } 144 | 145 | for _, sc := range txScenarios { 146 | t.Run(sc.Description, func(t *testing.T) { 147 | builder := tx.NewTxBuilder( 148 | *pr, 149 | []bip32.XPrv{}, 150 | ) 151 | addr, utxoPrv, err := generateBaseAddress(network.MainNet()) 152 | if err != nil { 153 | log.Fatal(err) 154 | } 155 | 156 | builder.AddInputs( 157 | tx.NewTxInput( 158 | txD.UtxoIn.TxHash, 159 | uint16(txD.UtxoIn.TxIndex), 160 | txD.UtxoIn.AmountLovelace, 161 | ), 162 | ) 163 | 164 | builder.AddOutputs( 165 | tx.NewTxOutput( 166 | sc.AddrProc(addr), 167 | txD.AmountLovelace, 168 | ), 169 | ) 170 | 171 | changeAddr, err := address.NewAddress(txD.ChangeAddress) 172 | if err != nil { 173 | log.Fatal(err) 174 | } 175 | builder.SetTTL(uint32(txD.SlotNo)) 176 | builder.AddChangeIfNeeded(changeAddr) 177 | 178 | builder.Sign( 179 | utxoPrv, 180 | ) 181 | txFinal, err := builder.Build() 182 | if err != nil { 183 | t.Fatal(err) 184 | } 185 | 186 | txHex, err := txFinal.Hex() 187 | if err != nil { 188 | log.Fatal(err) 189 | } 190 | golden := filepath.Join(basepath, "testdata", "transaction", "tx_builder", "golden", sc.GoldenFile) 191 | assert.Equal(t, txHex, ReadOrGenerateGoldenFile(t, golden, txFinal)) 192 | }) 193 | } 194 | } 195 | 196 | func WriteGoldenFile(t *testing.T, path string, data []byte) { 197 | t.Helper() 198 | err := os.MkdirAll(filepath.Dir(path), 0777) 199 | if err != nil { 200 | t.Fatal(err) 201 | } 202 | err = ioutil.WriteFile(path, data, 0666) 203 | if err != nil { 204 | t.Fatal(err) 205 | } 206 | } 207 | 208 | func ReadOrGenerateGoldenFile(t *testing.T, path string, txF tx.Tx) string { 209 | t.Helper() 210 | b, err := ioutil.ReadFile(path) 211 | switch { 212 | case errors.Is(err, os.ErrNotExist): 213 | if *generate { 214 | txHex, err := txF.Hex() 215 | if err != nil { 216 | t.Fatal("golden-gen: Failed to hex encode transaction") 217 | } 218 | if err != nil { 219 | t.Fatal("golden-gen: Failed to hex encode transaction") 220 | } 221 | WriteGoldenFile(t, path, []byte(txHex)) 222 | return txHex 223 | } 224 | t.Fatalf("golden-read: Missing golden file. Run `go test -args -gen` to generate it.") 225 | case err != nil: 226 | t.Fatal(err) 227 | } 228 | return string(b) 229 | } 230 | -------------------------------------------------------------------------------- /bip32/bip32.go: -------------------------------------------------------------------------------- 1 | package bip32 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | "crypto/sha512" 7 | "encoding/binary" 8 | "errors" 9 | 10 | "github.com/fivebinaries/go-cardano-serialization/crypto" 11 | "github.com/fivebinaries/go-cardano-serialization/crypto/edwards25519" 12 | "golang.org/x/crypto/pbkdf2" 13 | ) 14 | 15 | const ( 16 | XPrv_Size = 96 17 | SignatureLength = 64 18 | ) 19 | 20 | type XPrv []byte 21 | type XPub []byte 22 | type PublicKey []byte 23 | type PrivateKey []byte 24 | 25 | func NewXPrv(seed []byte) (XPrv, error) { 26 | // Let k~ be 256-bit master secret. 27 | if len(seed) != 32 { 28 | return XPrv{}, errors.New("seed needs to be 256 bits long") 29 | } 30 | 31 | // Then derive k = H_512(k~) and denote its left 32-byte by k_L and right one by k_R. 32 | extendedPrivateKey := sha512.Sum512(seed) 33 | 34 | // Otherwise additionally set the bits in k_L as follows: 35 | // The lowest 3 bits of the first byte of k_L are cleared. 36 | extendedPrivateKey[0] &= 0b_1111_1000 37 | // The highest bit of the last byte is cleared. 38 | // If the third highest bit of the last byte of k_L is not zero, discard k~. 39 | extendedPrivateKey[31] &= 0b_0101_1111 40 | // The second highest bit of the last byte is set 41 | extendedPrivateKey[31] |= 0b_0100_0000 42 | 43 | // The resulting pair (k_L, k_R) is the extended root private key. 44 | 45 | // And A <- [k_L]B is the root public key after encoding. 46 | 47 | // Derive c <- H_256(0x01 || k~) and call it the root chain code. 48 | rootChainCode := sha256.Sum256(append([]byte{0x01}, seed...)) 49 | 50 | return append(extendedPrivateKey[:], rootChainCode[:]...), nil 51 | } 52 | 53 | func isHardened(index uint32) bool { 54 | return index >= 0x80000000 55 | } 56 | 57 | func (key XPrv) publicKey() [crypto.PublicKeyLen]byte { 58 | return MakePublicKey(key.extendedPrivateKey()) 59 | } 60 | 61 | func (key XPrv) extendedPrivateKey() []byte { 62 | return key[:64] 63 | } 64 | 65 | func (key XPrv) ChainCode() []byte { 66 | return key[64:] 67 | } 68 | 69 | func add28mul8(x, y []byte) []byte { 70 | var carry uint16 71 | 72 | out := make([]byte, 32) 73 | for i := 0; i < 28; i++ { 74 | r := uint16(x[i]) + (uint16(y[i]) << 3) + carry 75 | out[i] = byte(r & 0xff) 76 | carry = r >> 8 77 | } 78 | for i := 28; i < 32; i++ { 79 | r := uint16(x[i]) + carry 80 | out[i] = byte(r & 0xff) 81 | carry = r >> 8 82 | } 83 | return out 84 | } 85 | 86 | func add256bits(x, y []byte) []byte { 87 | var carry uint16 88 | 89 | out := make([]byte, 32) 90 | for i := 0; i < 32; i++ { 91 | r := uint16(x[i]) + uint16(y[i]) + carry 92 | out[i] = byte(r & 0xff) 93 | carry = r >> 8 94 | } 95 | return out 96 | } 97 | 98 | func (key XPrv) Derive(index uint32) XPrv { 99 | zmac := hmac.New(sha512.New, key.ChainCode()) 100 | imac := hmac.New(sha512.New, key.ChainCode()) 101 | 102 | serializedIndex := make([]byte, 4) 103 | binary.LittleEndian.PutUint32(serializedIndex, index) 104 | //hash.Write(serializedIndex) 105 | if isHardened(index) { 106 | // pk := []byte(ed25519.PrivateKey(key.extendedPrivateKey()).Public()) 107 | zmac.Write([]byte{0x00}) 108 | zmac.Write(key.extendedPrivateKey()) 109 | zmac.Write(serializedIndex) 110 | imac.Write([]byte{0x01}) 111 | imac.Write(key.extendedPrivateKey()) 112 | imac.Write(serializedIndex) 113 | } else { 114 | pk := MakePublicKey(key.extendedPrivateKey()) 115 | zmac.Write([]byte{0x02}) 116 | zmac.Write(pk[:]) 117 | zmac.Write(serializedIndex) 118 | imac.Write([]byte{0x03}) 119 | imac.Write(pk[:]) 120 | imac.Write(serializedIndex) 121 | } 122 | 123 | zout := zmac.Sum(nil) 124 | iout := imac.Sum(nil) 125 | 126 | left := add28mul8(key[:32], zout[:32]) 127 | right := add256bits(key[32:64], zout[32:64]) 128 | 129 | out := make([]byte, 0, 92) 130 | out = append(out, left...) 131 | out = append(out, right...) 132 | out = append(out, iout[32:]...) 133 | 134 | imac.Reset() 135 | zmac.Reset() 136 | 137 | return out 138 | } 139 | 140 | func (key XPrv) Public() XPub { 141 | out := make([]byte, 0, 64) 142 | pk := key.publicKey() 143 | out = append(out, pk[:]...) 144 | out = append(out, key.ChainCode()...) 145 | return out 146 | } 147 | 148 | func (pub XPub) PublicKey() PublicKey { 149 | return PublicKey(pub[:32]) 150 | } 151 | 152 | func (pub XPub) ChainCode() PrivateKey { 153 | return PrivateKey(pub[32:]) 154 | } 155 | 156 | //implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/chain_crypto/derive.rs#L30 157 | //implements https://github.com/Emurgo/cardano-serialization-lib/blob/0e89deadf9183a129b9a25c0568eed177d6c6d7c/rust/src/crypto.rs#L123 158 | func FromBip39Entropy(entropy []byte, password []byte) XPrv { 159 | const Iter = 4096 160 | pbkdf2_result := pbkdf2.Key(password, entropy, Iter, XPrv_Size, sha512.New) 161 | return NormalizeBytesForce3rd(pbkdf2_result) 162 | } 163 | 164 | func NormalizeBytesForce3rd(bytes []byte) XPrv { 165 | bytes[0] &= 0b1111_1000 166 | bytes[31] &= 0b0001_1111 167 | bytes[31] |= 0b0100_0000 168 | return bytes 169 | } 170 | 171 | func (pub PublicKey) Hash() crypto.Ed25519KeyHash { 172 | return crypto.Blake2b224(pub) 173 | } 174 | 175 | func MakePublicKey(extendedSecret []byte) [crypto.PublicKeyLen]byte { 176 | var result [crypto.PublicKeyLen]byte 177 | var key [crypto.PublicKeyLen]byte 178 | copy(key[:], extendedSecret[:32]) 179 | 180 | h := edwards25519.ExtendedGroupElement{} 181 | edwards25519.GeScalarMultBase(&h, &key) 182 | h.ToBytes(&result) 183 | return result 184 | } 185 | 186 | //func FromNormalBytes(bytes []byte) (XPrv, error) { 187 | // 188 | //} 189 | 190 | func getFilledArray(length int, val byte) []byte { 191 | var res []byte 192 | for len(res) < length { 193 | res = append(res, val) 194 | } 195 | return res 196 | } 197 | 198 | func (prv *XPrv) Sign(message []byte) [SignatureLength]byte { 199 | publicKey := MakePublicKey((*prv)) 200 | 201 | hasher := sha512.New() 202 | hasher.Write((*prv)[32:64]) 203 | hasher.Write(message) 204 | hashOutput := hasher.Sum(nil) 205 | var nonce [32]byte 206 | var hashFull [64]byte 207 | copy(hashFull[:], hashOutput[:64]) 208 | edwards25519.ScReduce(&nonce, &hashFull) 209 | 210 | var signature [SignatureLength]byte 211 | copy(signature[:], getFilledArray(SignatureLength, 0)) 212 | 213 | var r [32]byte 214 | h := edwards25519.ExtendedGroupElement{} 215 | edwards25519.GeScalarMultBase(&h, &nonce) 216 | h.ToBytes(&r) 217 | 218 | copy(signature[:32], r[:]) 219 | copy(signature[32:64], publicKey[:]) 220 | 221 | hasher = sha512.New() 222 | hasher.Write(signature[:]) 223 | hasher.Write(message) 224 | var hram [64]byte 225 | hramTmp := hasher.Sum(nil) 226 | copy(hram[:], hramTmp) 227 | var hramReduced [32]byte 228 | edwards25519.ScReduce(&hramReduced, &hram) 229 | var s [32]byte 230 | var b [32]byte 231 | copy(s[:], signature[32:64]) 232 | copy(b[:], (*prv)[0:32]) 233 | edwards25519.ScMulAdd(&s, &hramReduced, &b, &nonce) 234 | copy(signature[32:], s[:]) 235 | return signature 236 | } 237 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= 2 | github.com/blockfrost/blockfrost-go v0.1.0 h1:s9+kk1L2pM+GEZZCZxX7z6+1eNYyyFFX0lUVp6fUgx8= 3 | github.com/blockfrost/blockfrost-go v0.1.0/go.mod h1:TYp7iHyuEm87IrTziSUA2+UaAor8a1lGGR499YyfPO4= 4 | github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= 5 | github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= 6 | github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= 7 | github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= 8 | github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= 9 | github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= 10 | github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= 11 | github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= 12 | github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= 13 | github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= 14 | github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 19 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 20 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 21 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 22 | github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= 23 | github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= 24 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 25 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 26 | github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 27 | github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 28 | github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 29 | github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= 30 | github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 31 | github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= 32 | github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= 33 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 34 | github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 35 | github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= 36 | github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= 37 | github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 38 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 39 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 40 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 41 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 42 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 43 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 44 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= 45 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 46 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 47 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 48 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 49 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 50 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 51 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 52 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 53 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 54 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 55 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 56 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 57 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 58 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 59 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 60 | github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= 61 | github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= 62 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 63 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 64 | golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 65 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 67 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 68 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 h1:XdAboW3BNMv9ocSCOk/u1MFioZGzCNkiJZ19v9Oe3Ig= 69 | golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 70 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 71 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 72 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 73 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 74 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 75 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 76 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 77 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 78 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 80 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 81 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 83 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 84 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 85 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 86 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= 87 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 88 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 89 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 90 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 91 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 92 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 93 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 94 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 95 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 96 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 97 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 98 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 99 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 100 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /crypto/edwards25519/edwards25519.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package edwards25519 6 | 7 | import "encoding/binary" 8 | 9 | // This code is a port of the public domain, “ref10” implementation of ed25519 10 | // from SUPERCOP. 11 | 12 | // FieldElement represents an element of the field GF(2^255 - 19). An element 13 | // t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 14 | // t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on 15 | // context. 16 | type FieldElement [10]int32 17 | 18 | var zero FieldElement 19 | 20 | func FeZero(fe *FieldElement) { 21 | copy(fe[:], zero[:]) 22 | } 23 | 24 | func FeOne(fe *FieldElement) { 25 | FeZero(fe) 26 | fe[0] = 1 27 | } 28 | 29 | func FeAdd(dst, a, b *FieldElement) { 30 | dst[0] = a[0] + b[0] 31 | dst[1] = a[1] + b[1] 32 | dst[2] = a[2] + b[2] 33 | dst[3] = a[3] + b[3] 34 | dst[4] = a[4] + b[4] 35 | dst[5] = a[5] + b[5] 36 | dst[6] = a[6] + b[6] 37 | dst[7] = a[7] + b[7] 38 | dst[8] = a[8] + b[8] 39 | dst[9] = a[9] + b[9] 40 | } 41 | 42 | func FeSub(dst, a, b *FieldElement) { 43 | dst[0] = a[0] - b[0] 44 | dst[1] = a[1] - b[1] 45 | dst[2] = a[2] - b[2] 46 | dst[3] = a[3] - b[3] 47 | dst[4] = a[4] - b[4] 48 | dst[5] = a[5] - b[5] 49 | dst[6] = a[6] - b[6] 50 | dst[7] = a[7] - b[7] 51 | dst[8] = a[8] - b[8] 52 | dst[9] = a[9] - b[9] 53 | } 54 | 55 | func FeCopy(dst, src *FieldElement) { 56 | copy(dst[:], src[:]) 57 | } 58 | 59 | // Replace (f,g) with (g,g) if b == 1; 60 | // replace (f,g) with (f,g) if b == 0. 61 | // 62 | // Preconditions: b in {0,1}. 63 | func FeCMove(f, g *FieldElement, b int32) { 64 | b = -b 65 | f[0] ^= b & (f[0] ^ g[0]) 66 | f[1] ^= b & (f[1] ^ g[1]) 67 | f[2] ^= b & (f[2] ^ g[2]) 68 | f[3] ^= b & (f[3] ^ g[3]) 69 | f[4] ^= b & (f[4] ^ g[4]) 70 | f[5] ^= b & (f[5] ^ g[5]) 71 | f[6] ^= b & (f[6] ^ g[6]) 72 | f[7] ^= b & (f[7] ^ g[7]) 73 | f[8] ^= b & (f[8] ^ g[8]) 74 | f[9] ^= b & (f[9] ^ g[9]) 75 | } 76 | 77 | func load3(in []byte) int64 { 78 | var r int64 79 | r = int64(in[0]) 80 | r |= int64(in[1]) << 8 81 | r |= int64(in[2]) << 16 82 | return r 83 | } 84 | 85 | func load4(in []byte) int64 { 86 | var r int64 87 | r = int64(in[0]) 88 | r |= int64(in[1]) << 8 89 | r |= int64(in[2]) << 16 90 | r |= int64(in[3]) << 24 91 | return r 92 | } 93 | 94 | func FeFromBytes(dst *FieldElement, src *[32]byte) { 95 | h0 := load4(src[:]) 96 | h1 := load3(src[4:]) << 6 97 | h2 := load3(src[7:]) << 5 98 | h3 := load3(src[10:]) << 3 99 | h4 := load3(src[13:]) << 2 100 | h5 := load4(src[16:]) 101 | h6 := load3(src[20:]) << 7 102 | h7 := load3(src[23:]) << 5 103 | h8 := load3(src[26:]) << 4 104 | h9 := (load3(src[29:]) & 8388607) << 2 105 | 106 | FeCombine(dst, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) 107 | } 108 | 109 | // FeToBytes marshals h to s. 110 | // Preconditions: 111 | // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 112 | // 113 | // Write p=2^255-19; q=floor(h/p). 114 | // Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). 115 | // 116 | // Proof: 117 | // Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. 118 | // Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. 119 | // 120 | // Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). 121 | // Then 0> 25 136 | q = (h[0] + q) >> 26 137 | q = (h[1] + q) >> 25 138 | q = (h[2] + q) >> 26 139 | q = (h[3] + q) >> 25 140 | q = (h[4] + q) >> 26 141 | q = (h[5] + q) >> 25 142 | q = (h[6] + q) >> 26 143 | q = (h[7] + q) >> 25 144 | q = (h[8] + q) >> 26 145 | q = (h[9] + q) >> 25 146 | 147 | // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. 148 | h[0] += 19 * q 149 | // Goal: Output h-2^255 q, which is between 0 and 2^255-20. 150 | 151 | carry[0] = h[0] >> 26 152 | h[1] += carry[0] 153 | h[0] -= carry[0] << 26 154 | carry[1] = h[1] >> 25 155 | h[2] += carry[1] 156 | h[1] -= carry[1] << 25 157 | carry[2] = h[2] >> 26 158 | h[3] += carry[2] 159 | h[2] -= carry[2] << 26 160 | carry[3] = h[3] >> 25 161 | h[4] += carry[3] 162 | h[3] -= carry[3] << 25 163 | carry[4] = h[4] >> 26 164 | h[5] += carry[4] 165 | h[4] -= carry[4] << 26 166 | carry[5] = h[5] >> 25 167 | h[6] += carry[5] 168 | h[5] -= carry[5] << 25 169 | carry[6] = h[6] >> 26 170 | h[7] += carry[6] 171 | h[6] -= carry[6] << 26 172 | carry[7] = h[7] >> 25 173 | h[8] += carry[7] 174 | h[7] -= carry[7] << 25 175 | carry[8] = h[8] >> 26 176 | h[9] += carry[8] 177 | h[8] -= carry[8] << 26 178 | carry[9] = h[9] >> 25 179 | h[9] -= carry[9] << 25 180 | // h10 = carry9 181 | 182 | // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. 183 | // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; 184 | // evidently 2^255 h10-2^255 q = 0. 185 | // Goal: Output h[0]+...+2^230 h[9]. 186 | 187 | s[0] = byte(h[0] >> 0) 188 | s[1] = byte(h[0] >> 8) 189 | s[2] = byte(h[0] >> 16) 190 | s[3] = byte((h[0] >> 24) | (h[1] << 2)) 191 | s[4] = byte(h[1] >> 6) 192 | s[5] = byte(h[1] >> 14) 193 | s[6] = byte((h[1] >> 22) | (h[2] << 3)) 194 | s[7] = byte(h[2] >> 5) 195 | s[8] = byte(h[2] >> 13) 196 | s[9] = byte((h[2] >> 21) | (h[3] << 5)) 197 | s[10] = byte(h[3] >> 3) 198 | s[11] = byte(h[3] >> 11) 199 | s[12] = byte((h[3] >> 19) | (h[4] << 6)) 200 | s[13] = byte(h[4] >> 2) 201 | s[14] = byte(h[4] >> 10) 202 | s[15] = byte(h[4] >> 18) 203 | s[16] = byte(h[5] >> 0) 204 | s[17] = byte(h[5] >> 8) 205 | s[18] = byte(h[5] >> 16) 206 | s[19] = byte((h[5] >> 24) | (h[6] << 1)) 207 | s[20] = byte(h[6] >> 7) 208 | s[21] = byte(h[6] >> 15) 209 | s[22] = byte((h[6] >> 23) | (h[7] << 3)) 210 | s[23] = byte(h[7] >> 5) 211 | s[24] = byte(h[7] >> 13) 212 | s[25] = byte((h[7] >> 21) | (h[8] << 4)) 213 | s[26] = byte(h[8] >> 4) 214 | s[27] = byte(h[8] >> 12) 215 | s[28] = byte((h[8] >> 20) | (h[9] << 6)) 216 | s[29] = byte(h[9] >> 2) 217 | s[30] = byte(h[9] >> 10) 218 | s[31] = byte(h[9] >> 18) 219 | } 220 | 221 | func FeIsNegative(f *FieldElement) byte { 222 | var s [32]byte 223 | FeToBytes(&s, f) 224 | return s[0] & 1 225 | } 226 | 227 | func FeIsNonZero(f *FieldElement) int32 { 228 | var s [32]byte 229 | FeToBytes(&s, f) 230 | var x uint8 231 | for _, b := range s { 232 | x |= b 233 | } 234 | x |= x >> 4 235 | x |= x >> 2 236 | x |= x >> 1 237 | return int32(x & 1) 238 | } 239 | 240 | // FeNeg sets h = -f 241 | // 242 | // Preconditions: 243 | // |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 244 | // 245 | // Postconditions: 246 | // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 247 | func FeNeg(h, f *FieldElement) { 248 | h[0] = -f[0] 249 | h[1] = -f[1] 250 | h[2] = -f[2] 251 | h[3] = -f[3] 252 | h[4] = -f[4] 253 | h[5] = -f[5] 254 | h[6] = -f[6] 255 | h[7] = -f[7] 256 | h[8] = -f[8] 257 | h[9] = -f[9] 258 | } 259 | 260 | func FeCombine(h *FieldElement, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { 261 | var c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 int64 262 | 263 | /* 264 | |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) 265 | i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 266 | |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) 267 | i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 268 | */ 269 | 270 | c0 = (h0 + (1 << 25)) >> 26 271 | h1 += c0 272 | h0 -= c0 << 26 273 | c4 = (h4 + (1 << 25)) >> 26 274 | h5 += c4 275 | h4 -= c4 << 26 276 | /* |h0| <= 2^25 */ 277 | /* |h4| <= 2^25 */ 278 | /* |h1| <= 1.51*2^58 */ 279 | /* |h5| <= 1.51*2^58 */ 280 | 281 | c1 = (h1 + (1 << 24)) >> 25 282 | h2 += c1 283 | h1 -= c1 << 25 284 | c5 = (h5 + (1 << 24)) >> 25 285 | h6 += c5 286 | h5 -= c5 << 25 287 | /* |h1| <= 2^24; from now on fits into int32 */ 288 | /* |h5| <= 2^24; from now on fits into int32 */ 289 | /* |h2| <= 1.21*2^59 */ 290 | /* |h6| <= 1.21*2^59 */ 291 | 292 | c2 = (h2 + (1 << 25)) >> 26 293 | h3 += c2 294 | h2 -= c2 << 26 295 | c6 = (h6 + (1 << 25)) >> 26 296 | h7 += c6 297 | h6 -= c6 << 26 298 | /* |h2| <= 2^25; from now on fits into int32 unchanged */ 299 | /* |h6| <= 2^25; from now on fits into int32 unchanged */ 300 | /* |h3| <= 1.51*2^58 */ 301 | /* |h7| <= 1.51*2^58 */ 302 | 303 | c3 = (h3 + (1 << 24)) >> 25 304 | h4 += c3 305 | h3 -= c3 << 25 306 | c7 = (h7 + (1 << 24)) >> 25 307 | h8 += c7 308 | h7 -= c7 << 25 309 | /* |h3| <= 2^24; from now on fits into int32 unchanged */ 310 | /* |h7| <= 2^24; from now on fits into int32 unchanged */ 311 | /* |h4| <= 1.52*2^33 */ 312 | /* |h8| <= 1.52*2^33 */ 313 | 314 | c4 = (h4 + (1 << 25)) >> 26 315 | h5 += c4 316 | h4 -= c4 << 26 317 | c8 = (h8 + (1 << 25)) >> 26 318 | h9 += c8 319 | h8 -= c8 << 26 320 | /* |h4| <= 2^25; from now on fits into int32 unchanged */ 321 | /* |h8| <= 2^25; from now on fits into int32 unchanged */ 322 | /* |h5| <= 1.01*2^24 */ 323 | /* |h9| <= 1.51*2^58 */ 324 | 325 | c9 = (h9 + (1 << 24)) >> 25 326 | h0 += c9 * 19 327 | h9 -= c9 << 25 328 | /* |h9| <= 2^24; from now on fits into int32 unchanged */ 329 | /* |h0| <= 1.8*2^37 */ 330 | 331 | c0 = (h0 + (1 << 25)) >> 26 332 | h1 += c0 333 | h0 -= c0 << 26 334 | /* |h0| <= 2^25; from now on fits into int32 unchanged */ 335 | /* |h1| <= 1.01*2^24 */ 336 | 337 | h[0] = int32(h0) 338 | h[1] = int32(h1) 339 | h[2] = int32(h2) 340 | h[3] = int32(h3) 341 | h[4] = int32(h4) 342 | h[5] = int32(h5) 343 | h[6] = int32(h6) 344 | h[7] = int32(h7) 345 | h[8] = int32(h8) 346 | h[9] = int32(h9) 347 | } 348 | 349 | // FeMul calculates h = f * g 350 | // Can overlap h with f or g. 351 | // 352 | // Preconditions: 353 | // |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 354 | // |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 355 | // 356 | // Postconditions: 357 | // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 358 | // 359 | // Notes on implementation strategy: 360 | // 361 | // Using schoolbook multiplication. 362 | // Karatsuba would save a little in some cost models. 363 | // 364 | // Most multiplications by 2 and 19 are 32-bit precomputations; 365 | // cheaper than 64-bit postcomputations. 366 | // 367 | // There is one remaining multiplication by 19 in the carry chain; 368 | // one *19 precomputation can be merged into this, 369 | // but the resulting data flow is considerably less clean. 370 | // 371 | // There are 12 carries below. 372 | // 10 of them are 2-way parallelizable and vectorizable. 373 | // Can get away with 11 carries, but then data flow is much deeper. 374 | // 375 | // With tighter constraints on inputs, can squeeze carries into int32. 376 | func FeMul(h, f, g *FieldElement) { 377 | f0 := int64(f[0]) 378 | f1 := int64(f[1]) 379 | f2 := int64(f[2]) 380 | f3 := int64(f[3]) 381 | f4 := int64(f[4]) 382 | f5 := int64(f[5]) 383 | f6 := int64(f[6]) 384 | f7 := int64(f[7]) 385 | f8 := int64(f[8]) 386 | f9 := int64(f[9]) 387 | 388 | f1_2 := int64(2 * f[1]) 389 | f3_2 := int64(2 * f[3]) 390 | f5_2 := int64(2 * f[5]) 391 | f7_2 := int64(2 * f[7]) 392 | f9_2 := int64(2 * f[9]) 393 | 394 | g0 := int64(g[0]) 395 | g1 := int64(g[1]) 396 | g2 := int64(g[2]) 397 | g3 := int64(g[3]) 398 | g4 := int64(g[4]) 399 | g5 := int64(g[5]) 400 | g6 := int64(g[6]) 401 | g7 := int64(g[7]) 402 | g8 := int64(g[8]) 403 | g9 := int64(g[9]) 404 | 405 | g1_19 := int64(19 * g[1]) /* 1.4*2^29 */ 406 | g2_19 := int64(19 * g[2]) /* 1.4*2^30; still ok */ 407 | g3_19 := int64(19 * g[3]) 408 | g4_19 := int64(19 * g[4]) 409 | g5_19 := int64(19 * g[5]) 410 | g6_19 := int64(19 * g[6]) 411 | g7_19 := int64(19 * g[7]) 412 | g8_19 := int64(19 * g[8]) 413 | g9_19 := int64(19 * g[9]) 414 | 415 | h0 := f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19 416 | h1 := f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19 417 | h2 := f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19 418 | h3 := f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19 419 | h4 := f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19 420 | h5 := f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19 421 | h6 := f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19 422 | h7 := f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19 423 | h8 := f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19 424 | h9 := f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0 425 | 426 | FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) 427 | } 428 | 429 | func feSquare(f *FieldElement) (h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { 430 | f0 := int64(f[0]) 431 | f1 := int64(f[1]) 432 | f2 := int64(f[2]) 433 | f3 := int64(f[3]) 434 | f4 := int64(f[4]) 435 | f5 := int64(f[5]) 436 | f6 := int64(f[6]) 437 | f7 := int64(f[7]) 438 | f8 := int64(f[8]) 439 | f9 := int64(f[9]) 440 | f0_2 := int64(2 * f[0]) 441 | f1_2 := int64(2 * f[1]) 442 | f2_2 := int64(2 * f[2]) 443 | f3_2 := int64(2 * f[3]) 444 | f4_2 := int64(2 * f[4]) 445 | f5_2 := int64(2 * f[5]) 446 | f6_2 := int64(2 * f[6]) 447 | f7_2 := int64(2 * f[7]) 448 | f5_38 := 38 * f5 // 1.31*2^30 449 | f6_19 := 19 * f6 // 1.31*2^30 450 | f7_38 := 38 * f7 // 1.31*2^30 451 | f8_19 := 19 * f8 // 1.31*2^30 452 | f9_38 := 38 * f9 // 1.31*2^30 453 | 454 | h0 = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38 455 | h1 = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19 456 | h2 = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19 457 | h3 = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38 458 | h4 = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38 459 | h5 = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19 460 | h6 = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19 461 | h7 = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38 462 | h8 = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38 463 | h9 = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5 464 | 465 | return 466 | } 467 | 468 | // FeSquare calculates h = f*f. Can overlap h with f. 469 | // 470 | // Preconditions: 471 | // |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. 472 | // 473 | // Postconditions: 474 | // |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. 475 | func FeSquare(h, f *FieldElement) { 476 | h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) 477 | FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) 478 | } 479 | 480 | // FeSquare2 sets h = 2 * f * f 481 | // 482 | // Can overlap h with f. 483 | // 484 | // Preconditions: 485 | // |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. 486 | // 487 | // Postconditions: 488 | // |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. 489 | // See fe_mul.c for discussion of implementation strategy. 490 | func FeSquare2(h, f *FieldElement) { 491 | h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) 492 | 493 | h0 += h0 494 | h1 += h1 495 | h2 += h2 496 | h3 += h3 497 | h4 += h4 498 | h5 += h5 499 | h6 += h6 500 | h7 += h7 501 | h8 += h8 502 | h9 += h9 503 | 504 | FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) 505 | } 506 | 507 | func FeInvert(out, z *FieldElement) { 508 | var t0, t1, t2, t3 FieldElement 509 | var i int 510 | 511 | FeSquare(&t0, z) // 2^1 512 | FeSquare(&t1, &t0) // 2^2 513 | for i = 1; i < 2; i++ { // 2^3 514 | FeSquare(&t1, &t1) 515 | } 516 | FeMul(&t1, z, &t1) // 2^3 + 2^0 517 | FeMul(&t0, &t0, &t1) // 2^3 + 2^1 + 2^0 518 | FeSquare(&t2, &t0) // 2^4 + 2^2 + 2^1 519 | FeMul(&t1, &t1, &t2) // 2^4 + 2^3 + 2^2 + 2^1 + 2^0 520 | FeSquare(&t2, &t1) // 5,4,3,2,1 521 | for i = 1; i < 5; i++ { // 9,8,7,6,5 522 | FeSquare(&t2, &t2) 523 | } 524 | FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0 525 | FeSquare(&t2, &t1) // 10..1 526 | for i = 1; i < 10; i++ { // 19..10 527 | FeSquare(&t2, &t2) 528 | } 529 | FeMul(&t2, &t2, &t1) // 19..0 530 | FeSquare(&t3, &t2) // 20..1 531 | for i = 1; i < 20; i++ { // 39..20 532 | FeSquare(&t3, &t3) 533 | } 534 | FeMul(&t2, &t3, &t2) // 39..0 535 | FeSquare(&t2, &t2) // 40..1 536 | for i = 1; i < 10; i++ { // 49..10 537 | FeSquare(&t2, &t2) 538 | } 539 | FeMul(&t1, &t2, &t1) // 49..0 540 | FeSquare(&t2, &t1) // 50..1 541 | for i = 1; i < 50; i++ { // 99..50 542 | FeSquare(&t2, &t2) 543 | } 544 | FeMul(&t2, &t2, &t1) // 99..0 545 | FeSquare(&t3, &t2) // 100..1 546 | for i = 1; i < 100; i++ { // 199..100 547 | FeSquare(&t3, &t3) 548 | } 549 | FeMul(&t2, &t3, &t2) // 199..0 550 | FeSquare(&t2, &t2) // 200..1 551 | for i = 1; i < 50; i++ { // 249..50 552 | FeSquare(&t2, &t2) 553 | } 554 | FeMul(&t1, &t2, &t1) // 249..0 555 | FeSquare(&t1, &t1) // 250..1 556 | for i = 1; i < 5; i++ { // 254..5 557 | FeSquare(&t1, &t1) 558 | } 559 | FeMul(out, &t1, &t0) // 254..5,3,1,0 560 | } 561 | 562 | func fePow22523(out, z *FieldElement) { 563 | var t0, t1, t2 FieldElement 564 | var i int 565 | 566 | FeSquare(&t0, z) 567 | for i = 1; i < 1; i++ { 568 | FeSquare(&t0, &t0) 569 | } 570 | FeSquare(&t1, &t0) 571 | for i = 1; i < 2; i++ { 572 | FeSquare(&t1, &t1) 573 | } 574 | FeMul(&t1, z, &t1) 575 | FeMul(&t0, &t0, &t1) 576 | FeSquare(&t0, &t0) 577 | for i = 1; i < 1; i++ { 578 | FeSquare(&t0, &t0) 579 | } 580 | FeMul(&t0, &t1, &t0) 581 | FeSquare(&t1, &t0) 582 | for i = 1; i < 5; i++ { 583 | FeSquare(&t1, &t1) 584 | } 585 | FeMul(&t0, &t1, &t0) 586 | FeSquare(&t1, &t0) 587 | for i = 1; i < 10; i++ { 588 | FeSquare(&t1, &t1) 589 | } 590 | FeMul(&t1, &t1, &t0) 591 | FeSquare(&t2, &t1) 592 | for i = 1; i < 20; i++ { 593 | FeSquare(&t2, &t2) 594 | } 595 | FeMul(&t1, &t2, &t1) 596 | FeSquare(&t1, &t1) 597 | for i = 1; i < 10; i++ { 598 | FeSquare(&t1, &t1) 599 | } 600 | FeMul(&t0, &t1, &t0) 601 | FeSquare(&t1, &t0) 602 | for i = 1; i < 50; i++ { 603 | FeSquare(&t1, &t1) 604 | } 605 | FeMul(&t1, &t1, &t0) 606 | FeSquare(&t2, &t1) 607 | for i = 1; i < 100; i++ { 608 | FeSquare(&t2, &t2) 609 | } 610 | FeMul(&t1, &t2, &t1) 611 | FeSquare(&t1, &t1) 612 | for i = 1; i < 50; i++ { 613 | FeSquare(&t1, &t1) 614 | } 615 | FeMul(&t0, &t1, &t0) 616 | FeSquare(&t0, &t0) 617 | for i = 1; i < 2; i++ { 618 | FeSquare(&t0, &t0) 619 | } 620 | FeMul(out, &t0, z) 621 | } 622 | 623 | // Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 * 624 | // y^2 where d = -121665/121666. 625 | // 626 | // Several representations are used: 627 | // ProjectiveGroupElement: (X:Y:Z) satisfying x=X/Z, y=Y/Z 628 | // ExtendedGroupElement: (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT 629 | // CompletedGroupElement: ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T 630 | // PreComputedGroupElement: (y+x,y-x,2dxy) 631 | 632 | type ProjectiveGroupElement struct { 633 | X, Y, Z FieldElement 634 | } 635 | 636 | type ExtendedGroupElement struct { 637 | X, Y, Z, T FieldElement 638 | } 639 | 640 | type CompletedGroupElement struct { 641 | X, Y, Z, T FieldElement 642 | } 643 | 644 | type PreComputedGroupElement struct { 645 | yPlusX, yMinusX, xy2d FieldElement 646 | } 647 | 648 | type CachedGroupElement struct { 649 | yPlusX, yMinusX, Z, T2d FieldElement 650 | } 651 | 652 | func (p *ProjectiveGroupElement) Zero() { 653 | FeZero(&p.X) 654 | FeOne(&p.Y) 655 | FeOne(&p.Z) 656 | } 657 | 658 | func (p *ProjectiveGroupElement) Double(r *CompletedGroupElement) { 659 | var t0 FieldElement 660 | 661 | FeSquare(&r.X, &p.X) 662 | FeSquare(&r.Z, &p.Y) 663 | FeSquare2(&r.T, &p.Z) 664 | FeAdd(&r.Y, &p.X, &p.Y) 665 | FeSquare(&t0, &r.Y) 666 | FeAdd(&r.Y, &r.Z, &r.X) 667 | FeSub(&r.Z, &r.Z, &r.X) 668 | FeSub(&r.X, &t0, &r.Y) 669 | FeSub(&r.T, &r.T, &r.Z) 670 | } 671 | 672 | func (p *ProjectiveGroupElement) ToBytes(s *[32]byte) { 673 | var recip, x, y FieldElement 674 | 675 | FeInvert(&recip, &p.Z) 676 | FeMul(&x, &p.X, &recip) 677 | FeMul(&y, &p.Y, &recip) 678 | FeToBytes(s, &y) 679 | s[31] ^= FeIsNegative(&x) << 7 680 | } 681 | 682 | func (p *ExtendedGroupElement) Zero() { 683 | FeZero(&p.X) 684 | FeOne(&p.Y) 685 | FeOne(&p.Z) 686 | FeZero(&p.T) 687 | } 688 | 689 | func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) { 690 | var q ProjectiveGroupElement 691 | p.ToProjective(&q) 692 | q.Double(r) 693 | } 694 | 695 | func (p *ExtendedGroupElement) ToCached(r *CachedGroupElement) { 696 | FeAdd(&r.yPlusX, &p.Y, &p.X) 697 | FeSub(&r.yMinusX, &p.Y, &p.X) 698 | FeCopy(&r.Z, &p.Z) 699 | FeMul(&r.T2d, &p.T, &d2) 700 | } 701 | 702 | func (p *ExtendedGroupElement) ToProjective(r *ProjectiveGroupElement) { 703 | FeCopy(&r.X, &p.X) 704 | FeCopy(&r.Y, &p.Y) 705 | FeCopy(&r.Z, &p.Z) 706 | } 707 | 708 | func (p *ExtendedGroupElement) ToBytes(s *[32]byte) { 709 | var recip, x, y FieldElement 710 | 711 | FeInvert(&recip, &p.Z) 712 | FeMul(&x, &p.X, &recip) 713 | FeMul(&y, &p.Y, &recip) 714 | FeToBytes(s, &y) 715 | s[31] ^= FeIsNegative(&x) << 7 716 | } 717 | 718 | func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool { 719 | var u, v, v3, vxx, check FieldElement 720 | 721 | FeFromBytes(&p.Y, s) 722 | FeOne(&p.Z) 723 | FeSquare(&u, &p.Y) 724 | FeMul(&v, &u, &d) 725 | FeSub(&u, &u, &p.Z) // u = y^2-1 726 | FeAdd(&v, &v, &p.Z) // v = dy^2+1 727 | 728 | FeSquare(&v3, &v) 729 | FeMul(&v3, &v3, &v) // v3 = v^3 730 | FeSquare(&p.X, &v3) 731 | FeMul(&p.X, &p.X, &v) 732 | FeMul(&p.X, &p.X, &u) // x = uv^7 733 | 734 | fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8) 735 | FeMul(&p.X, &p.X, &v3) 736 | FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8) 737 | 738 | var tmpX, tmp2 [32]byte 739 | 740 | FeSquare(&vxx, &p.X) 741 | FeMul(&vxx, &vxx, &v) 742 | FeSub(&check, &vxx, &u) // vx^2-u 743 | if FeIsNonZero(&check) == 1 { 744 | FeAdd(&check, &vxx, &u) // vx^2+u 745 | if FeIsNonZero(&check) == 1 { 746 | return false 747 | } 748 | FeMul(&p.X, &p.X, &SqrtM1) 749 | 750 | FeToBytes(&tmpX, &p.X) 751 | for i, v := range tmpX { 752 | tmp2[31-i] = v 753 | } 754 | } 755 | 756 | if FeIsNegative(&p.X) != (s[31] >> 7) { 757 | FeNeg(&p.X, &p.X) 758 | } 759 | 760 | FeMul(&p.T, &p.X, &p.Y) 761 | return true 762 | } 763 | 764 | func (p *CompletedGroupElement) ToProjective(r *ProjectiveGroupElement) { 765 | FeMul(&r.X, &p.X, &p.T) 766 | FeMul(&r.Y, &p.Y, &p.Z) 767 | FeMul(&r.Z, &p.Z, &p.T) 768 | } 769 | 770 | func (p *CompletedGroupElement) ToExtended(r *ExtendedGroupElement) { 771 | FeMul(&r.X, &p.X, &p.T) 772 | FeMul(&r.Y, &p.Y, &p.Z) 773 | FeMul(&r.Z, &p.Z, &p.T) 774 | FeMul(&r.T, &p.X, &p.Y) 775 | } 776 | 777 | func (p *PreComputedGroupElement) Zero() { 778 | FeOne(&p.yPlusX) 779 | FeOne(&p.yMinusX) 780 | FeZero(&p.xy2d) 781 | } 782 | 783 | func geAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { 784 | var t0 FieldElement 785 | 786 | FeAdd(&r.X, &p.Y, &p.X) 787 | FeSub(&r.Y, &p.Y, &p.X) 788 | FeMul(&r.Z, &r.X, &q.yPlusX) 789 | FeMul(&r.Y, &r.Y, &q.yMinusX) 790 | FeMul(&r.T, &q.T2d, &p.T) 791 | FeMul(&r.X, &p.Z, &q.Z) 792 | FeAdd(&t0, &r.X, &r.X) 793 | FeSub(&r.X, &r.Z, &r.Y) 794 | FeAdd(&r.Y, &r.Z, &r.Y) 795 | FeAdd(&r.Z, &t0, &r.T) 796 | FeSub(&r.T, &t0, &r.T) 797 | } 798 | 799 | func geSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { 800 | var t0 FieldElement 801 | 802 | FeAdd(&r.X, &p.Y, &p.X) 803 | FeSub(&r.Y, &p.Y, &p.X) 804 | FeMul(&r.Z, &r.X, &q.yMinusX) 805 | FeMul(&r.Y, &r.Y, &q.yPlusX) 806 | FeMul(&r.T, &q.T2d, &p.T) 807 | FeMul(&r.X, &p.Z, &q.Z) 808 | FeAdd(&t0, &r.X, &r.X) 809 | FeSub(&r.X, &r.Z, &r.Y) 810 | FeAdd(&r.Y, &r.Z, &r.Y) 811 | FeSub(&r.Z, &t0, &r.T) 812 | FeAdd(&r.T, &t0, &r.T) 813 | } 814 | 815 | func geMixedAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { 816 | var t0 FieldElement 817 | 818 | FeAdd(&r.X, &p.Y, &p.X) 819 | FeSub(&r.Y, &p.Y, &p.X) 820 | FeMul(&r.Z, &r.X, &q.yPlusX) 821 | FeMul(&r.Y, &r.Y, &q.yMinusX) 822 | FeMul(&r.T, &q.xy2d, &p.T) 823 | FeAdd(&t0, &p.Z, &p.Z) 824 | FeSub(&r.X, &r.Z, &r.Y) 825 | FeAdd(&r.Y, &r.Z, &r.Y) 826 | FeAdd(&r.Z, &t0, &r.T) 827 | FeSub(&r.T, &t0, &r.T) 828 | } 829 | 830 | func geMixedSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { 831 | var t0 FieldElement 832 | 833 | FeAdd(&r.X, &p.Y, &p.X) 834 | FeSub(&r.Y, &p.Y, &p.X) 835 | FeMul(&r.Z, &r.X, &q.yMinusX) 836 | FeMul(&r.Y, &r.Y, &q.yPlusX) 837 | FeMul(&r.T, &q.xy2d, &p.T) 838 | FeAdd(&t0, &p.Z, &p.Z) 839 | FeSub(&r.X, &r.Z, &r.Y) 840 | FeAdd(&r.Y, &r.Z, &r.Y) 841 | FeSub(&r.Z, &t0, &r.T) 842 | FeAdd(&r.T, &t0, &r.T) 843 | } 844 | 845 | func slide(r *[256]int8, a *[32]byte) { 846 | for i := range r { 847 | r[i] = int8(1 & (a[i>>3] >> uint(i&7))) 848 | } 849 | 850 | for i := range r { 851 | if r[i] != 0 { 852 | for b := 1; b <= 6 && i+b < 256; b++ { 853 | if r[i+b] != 0 { 854 | if r[i]+(r[i+b]<= -15 { 858 | r[i] -= r[i+b] << uint(b) 859 | for k := i + b; k < 256; k++ { 860 | if r[k] == 0 { 861 | r[k] = 1 862 | break 863 | } 864 | r[k] = 0 865 | } 866 | } else { 867 | break 868 | } 869 | } 870 | } 871 | } 872 | } 873 | } 874 | 875 | // GeDoubleScalarMultVartime sets r = a*A + b*B 876 | // where a = a[0]+256*a[1]+...+256^31 a[31]. 877 | // and b = b[0]+256*b[1]+...+256^31 b[31]. 878 | // B is the Ed25519 base point (x,4/5) with x positive. 879 | func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *[32]byte, A *ExtendedGroupElement, b *[32]byte) { 880 | var aSlide, bSlide [256]int8 881 | var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A 882 | var t CompletedGroupElement 883 | var u, A2 ExtendedGroupElement 884 | var i int 885 | 886 | slide(&aSlide, a) 887 | slide(&bSlide, b) 888 | 889 | A.ToCached(&Ai[0]) 890 | A.Double(&t) 891 | t.ToExtended(&A2) 892 | 893 | for i := 0; i < 7; i++ { 894 | geAdd(&t, &A2, &Ai[i]) 895 | t.ToExtended(&u) 896 | u.ToCached(&Ai[i+1]) 897 | } 898 | 899 | r.Zero() 900 | 901 | for i = 255; i >= 0; i-- { 902 | if aSlide[i] != 0 || bSlide[i] != 0 { 903 | break 904 | } 905 | } 906 | 907 | for ; i >= 0; i-- { 908 | r.Double(&t) 909 | 910 | if aSlide[i] > 0 { 911 | t.ToExtended(&u) 912 | geAdd(&t, &u, &Ai[aSlide[i]/2]) 913 | } else if aSlide[i] < 0 { 914 | t.ToExtended(&u) 915 | geSub(&t, &u, &Ai[(-aSlide[i])/2]) 916 | } 917 | 918 | if bSlide[i] > 0 { 919 | t.ToExtended(&u) 920 | geMixedAdd(&t, &u, &bi[bSlide[i]/2]) 921 | } else if bSlide[i] < 0 { 922 | t.ToExtended(&u) 923 | geMixedSub(&t, &u, &bi[(-bSlide[i])/2]) 924 | } 925 | 926 | t.ToProjective(r) 927 | } 928 | } 929 | 930 | // equal returns 1 if b == c and 0 otherwise, assuming that b and c are 931 | // non-negative. 932 | func equal(b, c int32) int32 { 933 | x := uint32(b ^ c) 934 | x-- 935 | return int32(x >> 31) 936 | } 937 | 938 | // negative returns 1 if b < 0 and 0 otherwise. 939 | func negative(b int32) int32 { 940 | return (b >> 31) & 1 941 | } 942 | 943 | func PreComputedGroupElementCMove(t, u *PreComputedGroupElement, b int32) { 944 | FeCMove(&t.yPlusX, &u.yPlusX, b) 945 | FeCMove(&t.yMinusX, &u.yMinusX, b) 946 | FeCMove(&t.xy2d, &u.xy2d, b) 947 | } 948 | 949 | func selectPoint(t *PreComputedGroupElement, pos int32, b int32) { 950 | var minusT PreComputedGroupElement 951 | bNegative := negative(b) 952 | bAbs := b - (((-bNegative) & b) << 1) 953 | 954 | t.Zero() 955 | for i := int32(0); i < 8; i++ { 956 | PreComputedGroupElementCMove(t, &base[pos][i], equal(bAbs, i+1)) 957 | } 958 | FeCopy(&minusT.yPlusX, &t.yMinusX) 959 | FeCopy(&minusT.yMinusX, &t.yPlusX) 960 | FeNeg(&minusT.xy2d, &t.xy2d) 961 | PreComputedGroupElementCMove(t, &minusT, bNegative) 962 | } 963 | 964 | // GeScalarMultBase computes h = a*B, where 965 | // a = a[0]+256*a[1]+...+256^31 a[31] 966 | // B is the Ed25519 base point (x,4/5) with x positive. 967 | // 968 | // Preconditions: 969 | // a[31] <= 127 970 | func GeScalarMultBase(h *ExtendedGroupElement, a *[32]byte) { 971 | var e [64]int8 972 | 973 | for i, v := range a { 974 | e[2*i] = int8(v & 15) 975 | e[2*i+1] = int8((v >> 4) & 15) 976 | } 977 | 978 | // each e[i] is between 0 and 15 and e[63] is between 0 and 7. 979 | 980 | carry := int8(0) 981 | for i := 0; i < 63; i++ { 982 | e[i] += carry 983 | carry = (e[i] + 8) >> 4 984 | e[i] -= carry << 4 985 | } 986 | e[63] += carry 987 | // each e[i] is between -8 and 8. 988 | 989 | h.Zero() 990 | var t PreComputedGroupElement 991 | var r CompletedGroupElement 992 | for i := int32(1); i < 64; i += 2 { 993 | selectPoint(&t, i/2, int32(e[i])) 994 | geMixedAdd(&r, h, &t) 995 | r.ToExtended(h) 996 | } 997 | 998 | var s ProjectiveGroupElement 999 | 1000 | h.Double(&r) 1001 | r.ToProjective(&s) 1002 | s.Double(&r) 1003 | r.ToProjective(&s) 1004 | s.Double(&r) 1005 | r.ToProjective(&s) 1006 | s.Double(&r) 1007 | r.ToExtended(h) 1008 | 1009 | for i := int32(0); i < 64; i += 2 { 1010 | selectPoint(&t, i/2, int32(e[i])) 1011 | geMixedAdd(&r, h, &t) 1012 | r.ToExtended(h) 1013 | } 1014 | } 1015 | 1016 | // The scalars are GF(2^252 + 27742317777372353535851937790883648493). 1017 | 1018 | // Input: 1019 | // a[0]+256*a[1]+...+256^31*a[31] = a 1020 | // b[0]+256*b[1]+...+256^31*b[31] = b 1021 | // c[0]+256*c[1]+...+256^31*c[31] = c 1022 | // 1023 | // Output: 1024 | // s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l 1025 | // where l = 2^252 + 27742317777372353535851937790883648493. 1026 | func ScMulAdd(s, a, b, c *[32]byte) { 1027 | a0 := 2097151 & load3(a[:]) 1028 | a1 := 2097151 & (load4(a[2:]) >> 5) 1029 | a2 := 2097151 & (load3(a[5:]) >> 2) 1030 | a3 := 2097151 & (load4(a[7:]) >> 7) 1031 | a4 := 2097151 & (load4(a[10:]) >> 4) 1032 | a5 := 2097151 & (load3(a[13:]) >> 1) 1033 | a6 := 2097151 & (load4(a[15:]) >> 6) 1034 | a7 := 2097151 & (load3(a[18:]) >> 3) 1035 | a8 := 2097151 & load3(a[21:]) 1036 | a9 := 2097151 & (load4(a[23:]) >> 5) 1037 | a10 := 2097151 & (load3(a[26:]) >> 2) 1038 | a11 := (load4(a[28:]) >> 7) 1039 | b0 := 2097151 & load3(b[:]) 1040 | b1 := 2097151 & (load4(b[2:]) >> 5) 1041 | b2 := 2097151 & (load3(b[5:]) >> 2) 1042 | b3 := 2097151 & (load4(b[7:]) >> 7) 1043 | b4 := 2097151 & (load4(b[10:]) >> 4) 1044 | b5 := 2097151 & (load3(b[13:]) >> 1) 1045 | b6 := 2097151 & (load4(b[15:]) >> 6) 1046 | b7 := 2097151 & (load3(b[18:]) >> 3) 1047 | b8 := 2097151 & load3(b[21:]) 1048 | b9 := 2097151 & (load4(b[23:]) >> 5) 1049 | b10 := 2097151 & (load3(b[26:]) >> 2) 1050 | b11 := (load4(b[28:]) >> 7) 1051 | c0 := 2097151 & load3(c[:]) 1052 | c1 := 2097151 & (load4(c[2:]) >> 5) 1053 | c2 := 2097151 & (load3(c[5:]) >> 2) 1054 | c3 := 2097151 & (load4(c[7:]) >> 7) 1055 | c4 := 2097151 & (load4(c[10:]) >> 4) 1056 | c5 := 2097151 & (load3(c[13:]) >> 1) 1057 | c6 := 2097151 & (load4(c[15:]) >> 6) 1058 | c7 := 2097151 & (load3(c[18:]) >> 3) 1059 | c8 := 2097151 & load3(c[21:]) 1060 | c9 := 2097151 & (load4(c[23:]) >> 5) 1061 | c10 := 2097151 & (load3(c[26:]) >> 2) 1062 | c11 := (load4(c[28:]) >> 7) 1063 | var carry [23]int64 1064 | 1065 | s0 := c0 + a0*b0 1066 | s1 := c1 + a0*b1 + a1*b0 1067 | s2 := c2 + a0*b2 + a1*b1 + a2*b0 1068 | s3 := c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0 1069 | s4 := c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 1070 | s5 := c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0 1071 | s6 := c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0 1072 | s7 := c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0 1073 | s8 := c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0 1074 | s9 := c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0 1075 | s10 := c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0 1076 | 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 1077 | s12 := a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1 1078 | s13 := a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2 1079 | s14 := a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3 1080 | s15 := a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4 1081 | s16 := a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5 1082 | s17 := a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6 1083 | s18 := a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7 1084 | s19 := a8*b11 + a9*b10 + a10*b9 + a11*b8 1085 | s20 := a9*b11 + a10*b10 + a11*b9 1086 | s21 := a10*b11 + a11*b10 1087 | s22 := a11 * b11 1088 | s23 := int64(0) 1089 | 1090 | carry[0] = (s0 + (1 << 20)) >> 21 1091 | s1 += carry[0] 1092 | s0 -= carry[0] << 21 1093 | carry[2] = (s2 + (1 << 20)) >> 21 1094 | s3 += carry[2] 1095 | s2 -= carry[2] << 21 1096 | carry[4] = (s4 + (1 << 20)) >> 21 1097 | s5 += carry[4] 1098 | s4 -= carry[4] << 21 1099 | carry[6] = (s6 + (1 << 20)) >> 21 1100 | s7 += carry[6] 1101 | s6 -= carry[6] << 21 1102 | carry[8] = (s8 + (1 << 20)) >> 21 1103 | s9 += carry[8] 1104 | s8 -= carry[8] << 21 1105 | carry[10] = (s10 + (1 << 20)) >> 21 1106 | s11 += carry[10] 1107 | s10 -= carry[10] << 21 1108 | carry[12] = (s12 + (1 << 20)) >> 21 1109 | s13 += carry[12] 1110 | s12 -= carry[12] << 21 1111 | carry[14] = (s14 + (1 << 20)) >> 21 1112 | s15 += carry[14] 1113 | s14 -= carry[14] << 21 1114 | carry[16] = (s16 + (1 << 20)) >> 21 1115 | s17 += carry[16] 1116 | s16 -= carry[16] << 21 1117 | carry[18] = (s18 + (1 << 20)) >> 21 1118 | s19 += carry[18] 1119 | s18 -= carry[18] << 21 1120 | carry[20] = (s20 + (1 << 20)) >> 21 1121 | s21 += carry[20] 1122 | s20 -= carry[20] << 21 1123 | carry[22] = (s22 + (1 << 20)) >> 21 1124 | s23 += carry[22] 1125 | s22 -= carry[22] << 21 1126 | 1127 | carry[1] = (s1 + (1 << 20)) >> 21 1128 | s2 += carry[1] 1129 | s1 -= carry[1] << 21 1130 | carry[3] = (s3 + (1 << 20)) >> 21 1131 | s4 += carry[3] 1132 | s3 -= carry[3] << 21 1133 | carry[5] = (s5 + (1 << 20)) >> 21 1134 | s6 += carry[5] 1135 | s5 -= carry[5] << 21 1136 | carry[7] = (s7 + (1 << 20)) >> 21 1137 | s8 += carry[7] 1138 | s7 -= carry[7] << 21 1139 | carry[9] = (s9 + (1 << 20)) >> 21 1140 | s10 += carry[9] 1141 | s9 -= carry[9] << 21 1142 | carry[11] = (s11 + (1 << 20)) >> 21 1143 | s12 += carry[11] 1144 | s11 -= carry[11] << 21 1145 | carry[13] = (s13 + (1 << 20)) >> 21 1146 | s14 += carry[13] 1147 | s13 -= carry[13] << 21 1148 | carry[15] = (s15 + (1 << 20)) >> 21 1149 | s16 += carry[15] 1150 | s15 -= carry[15] << 21 1151 | carry[17] = (s17 + (1 << 20)) >> 21 1152 | s18 += carry[17] 1153 | s17 -= carry[17] << 21 1154 | carry[19] = (s19 + (1 << 20)) >> 21 1155 | s20 += carry[19] 1156 | s19 -= carry[19] << 21 1157 | carry[21] = (s21 + (1 << 20)) >> 21 1158 | s22 += carry[21] 1159 | s21 -= carry[21] << 21 1160 | 1161 | s11 += s23 * 666643 1162 | s12 += s23 * 470296 1163 | s13 += s23 * 654183 1164 | s14 -= s23 * 997805 1165 | s15 += s23 * 136657 1166 | s16 -= s23 * 683901 1167 | s23 = 0 1168 | 1169 | s10 += s22 * 666643 1170 | s11 += s22 * 470296 1171 | s12 += s22 * 654183 1172 | s13 -= s22 * 997805 1173 | s14 += s22 * 136657 1174 | s15 -= s22 * 683901 1175 | s22 = 0 1176 | 1177 | s9 += s21 * 666643 1178 | s10 += s21 * 470296 1179 | s11 += s21 * 654183 1180 | s12 -= s21 * 997805 1181 | s13 += s21 * 136657 1182 | s14 -= s21 * 683901 1183 | s21 = 0 1184 | 1185 | s8 += s20 * 666643 1186 | s9 += s20 * 470296 1187 | s10 += s20 * 654183 1188 | s11 -= s20 * 997805 1189 | s12 += s20 * 136657 1190 | s13 -= s20 * 683901 1191 | s20 = 0 1192 | 1193 | s7 += s19 * 666643 1194 | s8 += s19 * 470296 1195 | s9 += s19 * 654183 1196 | s10 -= s19 * 997805 1197 | s11 += s19 * 136657 1198 | s12 -= s19 * 683901 1199 | s19 = 0 1200 | 1201 | s6 += s18 * 666643 1202 | s7 += s18 * 470296 1203 | s8 += s18 * 654183 1204 | s9 -= s18 * 997805 1205 | s10 += s18 * 136657 1206 | s11 -= s18 * 683901 1207 | s18 = 0 1208 | 1209 | carry[6] = (s6 + (1 << 20)) >> 21 1210 | s7 += carry[6] 1211 | s6 -= carry[6] << 21 1212 | carry[8] = (s8 + (1 << 20)) >> 21 1213 | s9 += carry[8] 1214 | s8 -= carry[8] << 21 1215 | carry[10] = (s10 + (1 << 20)) >> 21 1216 | s11 += carry[10] 1217 | s10 -= carry[10] << 21 1218 | carry[12] = (s12 + (1 << 20)) >> 21 1219 | s13 += carry[12] 1220 | s12 -= carry[12] << 21 1221 | carry[14] = (s14 + (1 << 20)) >> 21 1222 | s15 += carry[14] 1223 | s14 -= carry[14] << 21 1224 | carry[16] = (s16 + (1 << 20)) >> 21 1225 | s17 += carry[16] 1226 | s16 -= carry[16] << 21 1227 | 1228 | carry[7] = (s7 + (1 << 20)) >> 21 1229 | s8 += carry[7] 1230 | s7 -= carry[7] << 21 1231 | carry[9] = (s9 + (1 << 20)) >> 21 1232 | s10 += carry[9] 1233 | s9 -= carry[9] << 21 1234 | carry[11] = (s11 + (1 << 20)) >> 21 1235 | s12 += carry[11] 1236 | s11 -= carry[11] << 21 1237 | carry[13] = (s13 + (1 << 20)) >> 21 1238 | s14 += carry[13] 1239 | s13 -= carry[13] << 21 1240 | carry[15] = (s15 + (1 << 20)) >> 21 1241 | s16 += carry[15] 1242 | s15 -= carry[15] << 21 1243 | 1244 | s5 += s17 * 666643 1245 | s6 += s17 * 470296 1246 | s7 += s17 * 654183 1247 | s8 -= s17 * 997805 1248 | s9 += s17 * 136657 1249 | s10 -= s17 * 683901 1250 | s17 = 0 1251 | 1252 | s4 += s16 * 666643 1253 | s5 += s16 * 470296 1254 | s6 += s16 * 654183 1255 | s7 -= s16 * 997805 1256 | s8 += s16 * 136657 1257 | s9 -= s16 * 683901 1258 | s16 = 0 1259 | 1260 | s3 += s15 * 666643 1261 | s4 += s15 * 470296 1262 | s5 += s15 * 654183 1263 | s6 -= s15 * 997805 1264 | s7 += s15 * 136657 1265 | s8 -= s15 * 683901 1266 | s15 = 0 1267 | 1268 | s2 += s14 * 666643 1269 | s3 += s14 * 470296 1270 | s4 += s14 * 654183 1271 | s5 -= s14 * 997805 1272 | s6 += s14 * 136657 1273 | s7 -= s14 * 683901 1274 | s14 = 0 1275 | 1276 | s1 += s13 * 666643 1277 | s2 += s13 * 470296 1278 | s3 += s13 * 654183 1279 | s4 -= s13 * 997805 1280 | s5 += s13 * 136657 1281 | s6 -= s13 * 683901 1282 | s13 = 0 1283 | 1284 | s0 += s12 * 666643 1285 | s1 += s12 * 470296 1286 | s2 += s12 * 654183 1287 | s3 -= s12 * 997805 1288 | s4 += s12 * 136657 1289 | s5 -= s12 * 683901 1290 | s12 = 0 1291 | 1292 | carry[0] = (s0 + (1 << 20)) >> 21 1293 | s1 += carry[0] 1294 | s0 -= carry[0] << 21 1295 | carry[2] = (s2 + (1 << 20)) >> 21 1296 | s3 += carry[2] 1297 | s2 -= carry[2] << 21 1298 | carry[4] = (s4 + (1 << 20)) >> 21 1299 | s5 += carry[4] 1300 | s4 -= carry[4] << 21 1301 | carry[6] = (s6 + (1 << 20)) >> 21 1302 | s7 += carry[6] 1303 | s6 -= carry[6] << 21 1304 | carry[8] = (s8 + (1 << 20)) >> 21 1305 | s9 += carry[8] 1306 | s8 -= carry[8] << 21 1307 | carry[10] = (s10 + (1 << 20)) >> 21 1308 | s11 += carry[10] 1309 | s10 -= carry[10] << 21 1310 | 1311 | carry[1] = (s1 + (1 << 20)) >> 21 1312 | s2 += carry[1] 1313 | s1 -= carry[1] << 21 1314 | carry[3] = (s3 + (1 << 20)) >> 21 1315 | s4 += carry[3] 1316 | s3 -= carry[3] << 21 1317 | carry[5] = (s5 + (1 << 20)) >> 21 1318 | s6 += carry[5] 1319 | s5 -= carry[5] << 21 1320 | carry[7] = (s7 + (1 << 20)) >> 21 1321 | s8 += carry[7] 1322 | s7 -= carry[7] << 21 1323 | carry[9] = (s9 + (1 << 20)) >> 21 1324 | s10 += carry[9] 1325 | s9 -= carry[9] << 21 1326 | carry[11] = (s11 + (1 << 20)) >> 21 1327 | s12 += carry[11] 1328 | s11 -= carry[11] << 21 1329 | 1330 | s0 += s12 * 666643 1331 | s1 += s12 * 470296 1332 | s2 += s12 * 654183 1333 | s3 -= s12 * 997805 1334 | s4 += s12 * 136657 1335 | s5 -= s12 * 683901 1336 | s12 = 0 1337 | 1338 | carry[0] = s0 >> 21 1339 | s1 += carry[0] 1340 | s0 -= carry[0] << 21 1341 | carry[1] = s1 >> 21 1342 | s2 += carry[1] 1343 | s1 -= carry[1] << 21 1344 | carry[2] = s2 >> 21 1345 | s3 += carry[2] 1346 | s2 -= carry[2] << 21 1347 | carry[3] = s3 >> 21 1348 | s4 += carry[3] 1349 | s3 -= carry[3] << 21 1350 | carry[4] = s4 >> 21 1351 | s5 += carry[4] 1352 | s4 -= carry[4] << 21 1353 | carry[5] = s5 >> 21 1354 | s6 += carry[5] 1355 | s5 -= carry[5] << 21 1356 | carry[6] = s6 >> 21 1357 | s7 += carry[6] 1358 | s6 -= carry[6] << 21 1359 | carry[7] = s7 >> 21 1360 | s8 += carry[7] 1361 | s7 -= carry[7] << 21 1362 | carry[8] = s8 >> 21 1363 | s9 += carry[8] 1364 | s8 -= carry[8] << 21 1365 | carry[9] = s9 >> 21 1366 | s10 += carry[9] 1367 | s9 -= carry[9] << 21 1368 | carry[10] = s10 >> 21 1369 | s11 += carry[10] 1370 | s10 -= carry[10] << 21 1371 | carry[11] = s11 >> 21 1372 | s12 += carry[11] 1373 | s11 -= carry[11] << 21 1374 | 1375 | s0 += s12 * 666643 1376 | s1 += s12 * 470296 1377 | s2 += s12 * 654183 1378 | s3 -= s12 * 997805 1379 | s4 += s12 * 136657 1380 | s5 -= s12 * 683901 1381 | s12 = 0 1382 | 1383 | carry[0] = s0 >> 21 1384 | s1 += carry[0] 1385 | s0 -= carry[0] << 21 1386 | carry[1] = s1 >> 21 1387 | s2 += carry[1] 1388 | s1 -= carry[1] << 21 1389 | carry[2] = s2 >> 21 1390 | s3 += carry[2] 1391 | s2 -= carry[2] << 21 1392 | carry[3] = s3 >> 21 1393 | s4 += carry[3] 1394 | s3 -= carry[3] << 21 1395 | carry[4] = s4 >> 21 1396 | s5 += carry[4] 1397 | s4 -= carry[4] << 21 1398 | carry[5] = s5 >> 21 1399 | s6 += carry[5] 1400 | s5 -= carry[5] << 21 1401 | carry[6] = s6 >> 21 1402 | s7 += carry[6] 1403 | s6 -= carry[6] << 21 1404 | carry[7] = s7 >> 21 1405 | s8 += carry[7] 1406 | s7 -= carry[7] << 21 1407 | carry[8] = s8 >> 21 1408 | s9 += carry[8] 1409 | s8 -= carry[8] << 21 1410 | carry[9] = s9 >> 21 1411 | s10 += carry[9] 1412 | s9 -= carry[9] << 21 1413 | carry[10] = s10 >> 21 1414 | s11 += carry[10] 1415 | s10 -= carry[10] << 21 1416 | 1417 | s[0] = byte(s0 >> 0) 1418 | s[1] = byte(s0 >> 8) 1419 | s[2] = byte((s0 >> 16) | (s1 << 5)) 1420 | s[3] = byte(s1 >> 3) 1421 | s[4] = byte(s1 >> 11) 1422 | s[5] = byte((s1 >> 19) | (s2 << 2)) 1423 | s[6] = byte(s2 >> 6) 1424 | s[7] = byte((s2 >> 14) | (s3 << 7)) 1425 | s[8] = byte(s3 >> 1) 1426 | s[9] = byte(s3 >> 9) 1427 | s[10] = byte((s3 >> 17) | (s4 << 4)) 1428 | s[11] = byte(s4 >> 4) 1429 | s[12] = byte(s4 >> 12) 1430 | s[13] = byte((s4 >> 20) | (s5 << 1)) 1431 | s[14] = byte(s5 >> 7) 1432 | s[15] = byte((s5 >> 15) | (s6 << 6)) 1433 | s[16] = byte(s6 >> 2) 1434 | s[17] = byte(s6 >> 10) 1435 | s[18] = byte((s6 >> 18) | (s7 << 3)) 1436 | s[19] = byte(s7 >> 5) 1437 | s[20] = byte(s7 >> 13) 1438 | s[21] = byte(s8 >> 0) 1439 | s[22] = byte(s8 >> 8) 1440 | s[23] = byte((s8 >> 16) | (s9 << 5)) 1441 | s[24] = byte(s9 >> 3) 1442 | s[25] = byte(s9 >> 11) 1443 | s[26] = byte((s9 >> 19) | (s10 << 2)) 1444 | s[27] = byte(s10 >> 6) 1445 | s[28] = byte((s10 >> 14) | (s11 << 7)) 1446 | s[29] = byte(s11 >> 1) 1447 | s[30] = byte(s11 >> 9) 1448 | s[31] = byte(s11 >> 17) 1449 | } 1450 | 1451 | // Input: 1452 | // s[0]+256*s[1]+...+256^63*s[63] = s 1453 | // 1454 | // Output: 1455 | // s[0]+256*s[1]+...+256^31*s[31] = s mod l 1456 | // where l = 2^252 + 27742317777372353535851937790883648493. 1457 | func ScReduce(out *[32]byte, s *[64]byte) { 1458 | s0 := 2097151 & load3(s[:]) 1459 | s1 := 2097151 & (load4(s[2:]) >> 5) 1460 | s2 := 2097151 & (load3(s[5:]) >> 2) 1461 | s3 := 2097151 & (load4(s[7:]) >> 7) 1462 | s4 := 2097151 & (load4(s[10:]) >> 4) 1463 | s5 := 2097151 & (load3(s[13:]) >> 1) 1464 | s6 := 2097151 & (load4(s[15:]) >> 6) 1465 | s7 := 2097151 & (load3(s[18:]) >> 3) 1466 | s8 := 2097151 & load3(s[21:]) 1467 | s9 := 2097151 & (load4(s[23:]) >> 5) 1468 | s10 := 2097151 & (load3(s[26:]) >> 2) 1469 | s11 := 2097151 & (load4(s[28:]) >> 7) 1470 | s12 := 2097151 & (load4(s[31:]) >> 4) 1471 | s13 := 2097151 & (load3(s[34:]) >> 1) 1472 | s14 := 2097151 & (load4(s[36:]) >> 6) 1473 | s15 := 2097151 & (load3(s[39:]) >> 3) 1474 | s16 := 2097151 & load3(s[42:]) 1475 | s17 := 2097151 & (load4(s[44:]) >> 5) 1476 | s18 := 2097151 & (load3(s[47:]) >> 2) 1477 | s19 := 2097151 & (load4(s[49:]) >> 7) 1478 | s20 := 2097151 & (load4(s[52:]) >> 4) 1479 | s21 := 2097151 & (load3(s[55:]) >> 1) 1480 | s22 := 2097151 & (load4(s[57:]) >> 6) 1481 | s23 := (load4(s[60:]) >> 3) 1482 | 1483 | s11 += s23 * 666643 1484 | s12 += s23 * 470296 1485 | s13 += s23 * 654183 1486 | s14 -= s23 * 997805 1487 | s15 += s23 * 136657 1488 | s16 -= s23 * 683901 1489 | s23 = 0 1490 | 1491 | s10 += s22 * 666643 1492 | s11 += s22 * 470296 1493 | s12 += s22 * 654183 1494 | s13 -= s22 * 997805 1495 | s14 += s22 * 136657 1496 | s15 -= s22 * 683901 1497 | s22 = 0 1498 | 1499 | s9 += s21 * 666643 1500 | s10 += s21 * 470296 1501 | s11 += s21 * 654183 1502 | s12 -= s21 * 997805 1503 | s13 += s21 * 136657 1504 | s14 -= s21 * 683901 1505 | s21 = 0 1506 | 1507 | s8 += s20 * 666643 1508 | s9 += s20 * 470296 1509 | s10 += s20 * 654183 1510 | s11 -= s20 * 997805 1511 | s12 += s20 * 136657 1512 | s13 -= s20 * 683901 1513 | s20 = 0 1514 | 1515 | s7 += s19 * 666643 1516 | s8 += s19 * 470296 1517 | s9 += s19 * 654183 1518 | s10 -= s19 * 997805 1519 | s11 += s19 * 136657 1520 | s12 -= s19 * 683901 1521 | s19 = 0 1522 | 1523 | s6 += s18 * 666643 1524 | s7 += s18 * 470296 1525 | s8 += s18 * 654183 1526 | s9 -= s18 * 997805 1527 | s10 += s18 * 136657 1528 | s11 -= s18 * 683901 1529 | s18 = 0 1530 | 1531 | var carry [17]int64 1532 | 1533 | carry[6] = (s6 + (1 << 20)) >> 21 1534 | s7 += carry[6] 1535 | s6 -= carry[6] << 21 1536 | carry[8] = (s8 + (1 << 20)) >> 21 1537 | s9 += carry[8] 1538 | s8 -= carry[8] << 21 1539 | carry[10] = (s10 + (1 << 20)) >> 21 1540 | s11 += carry[10] 1541 | s10 -= carry[10] << 21 1542 | carry[12] = (s12 + (1 << 20)) >> 21 1543 | s13 += carry[12] 1544 | s12 -= carry[12] << 21 1545 | carry[14] = (s14 + (1 << 20)) >> 21 1546 | s15 += carry[14] 1547 | s14 -= carry[14] << 21 1548 | carry[16] = (s16 + (1 << 20)) >> 21 1549 | s17 += carry[16] 1550 | s16 -= carry[16] << 21 1551 | 1552 | carry[7] = (s7 + (1 << 20)) >> 21 1553 | s8 += carry[7] 1554 | s7 -= carry[7] << 21 1555 | carry[9] = (s9 + (1 << 20)) >> 21 1556 | s10 += carry[9] 1557 | s9 -= carry[9] << 21 1558 | carry[11] = (s11 + (1 << 20)) >> 21 1559 | s12 += carry[11] 1560 | s11 -= carry[11] << 21 1561 | carry[13] = (s13 + (1 << 20)) >> 21 1562 | s14 += carry[13] 1563 | s13 -= carry[13] << 21 1564 | carry[15] = (s15 + (1 << 20)) >> 21 1565 | s16 += carry[15] 1566 | s15 -= carry[15] << 21 1567 | 1568 | s5 += s17 * 666643 1569 | s6 += s17 * 470296 1570 | s7 += s17 * 654183 1571 | s8 -= s17 * 997805 1572 | s9 += s17 * 136657 1573 | s10 -= s17 * 683901 1574 | s17 = 0 1575 | 1576 | s4 += s16 * 666643 1577 | s5 += s16 * 470296 1578 | s6 += s16 * 654183 1579 | s7 -= s16 * 997805 1580 | s8 += s16 * 136657 1581 | s9 -= s16 * 683901 1582 | s16 = 0 1583 | 1584 | s3 += s15 * 666643 1585 | s4 += s15 * 470296 1586 | s5 += s15 * 654183 1587 | s6 -= s15 * 997805 1588 | s7 += s15 * 136657 1589 | s8 -= s15 * 683901 1590 | s15 = 0 1591 | 1592 | s2 += s14 * 666643 1593 | s3 += s14 * 470296 1594 | s4 += s14 * 654183 1595 | s5 -= s14 * 997805 1596 | s6 += s14 * 136657 1597 | s7 -= s14 * 683901 1598 | s14 = 0 1599 | 1600 | s1 += s13 * 666643 1601 | s2 += s13 * 470296 1602 | s3 += s13 * 654183 1603 | s4 -= s13 * 997805 1604 | s5 += s13 * 136657 1605 | s6 -= s13 * 683901 1606 | s13 = 0 1607 | 1608 | s0 += s12 * 666643 1609 | s1 += s12 * 470296 1610 | s2 += s12 * 654183 1611 | s3 -= s12 * 997805 1612 | s4 += s12 * 136657 1613 | s5 -= s12 * 683901 1614 | s12 = 0 1615 | 1616 | carry[0] = (s0 + (1 << 20)) >> 21 1617 | s1 += carry[0] 1618 | s0 -= carry[0] << 21 1619 | carry[2] = (s2 + (1 << 20)) >> 21 1620 | s3 += carry[2] 1621 | s2 -= carry[2] << 21 1622 | carry[4] = (s4 + (1 << 20)) >> 21 1623 | s5 += carry[4] 1624 | s4 -= carry[4] << 21 1625 | carry[6] = (s6 + (1 << 20)) >> 21 1626 | s7 += carry[6] 1627 | s6 -= carry[6] << 21 1628 | carry[8] = (s8 + (1 << 20)) >> 21 1629 | s9 += carry[8] 1630 | s8 -= carry[8] << 21 1631 | carry[10] = (s10 + (1 << 20)) >> 21 1632 | s11 += carry[10] 1633 | s10 -= carry[10] << 21 1634 | 1635 | carry[1] = (s1 + (1 << 20)) >> 21 1636 | s2 += carry[1] 1637 | s1 -= carry[1] << 21 1638 | carry[3] = (s3 + (1 << 20)) >> 21 1639 | s4 += carry[3] 1640 | s3 -= carry[3] << 21 1641 | carry[5] = (s5 + (1 << 20)) >> 21 1642 | s6 += carry[5] 1643 | s5 -= carry[5] << 21 1644 | carry[7] = (s7 + (1 << 20)) >> 21 1645 | s8 += carry[7] 1646 | s7 -= carry[7] << 21 1647 | carry[9] = (s9 + (1 << 20)) >> 21 1648 | s10 += carry[9] 1649 | s9 -= carry[9] << 21 1650 | carry[11] = (s11 + (1 << 20)) >> 21 1651 | s12 += carry[11] 1652 | s11 -= carry[11] << 21 1653 | 1654 | s0 += s12 * 666643 1655 | s1 += s12 * 470296 1656 | s2 += s12 * 654183 1657 | s3 -= s12 * 997805 1658 | s4 += s12 * 136657 1659 | s5 -= s12 * 683901 1660 | s12 = 0 1661 | 1662 | carry[0] = s0 >> 21 1663 | s1 += carry[0] 1664 | s0 -= carry[0] << 21 1665 | carry[1] = s1 >> 21 1666 | s2 += carry[1] 1667 | s1 -= carry[1] << 21 1668 | carry[2] = s2 >> 21 1669 | s3 += carry[2] 1670 | s2 -= carry[2] << 21 1671 | carry[3] = s3 >> 21 1672 | s4 += carry[3] 1673 | s3 -= carry[3] << 21 1674 | carry[4] = s4 >> 21 1675 | s5 += carry[4] 1676 | s4 -= carry[4] << 21 1677 | carry[5] = s5 >> 21 1678 | s6 += carry[5] 1679 | s5 -= carry[5] << 21 1680 | carry[6] = s6 >> 21 1681 | s7 += carry[6] 1682 | s6 -= carry[6] << 21 1683 | carry[7] = s7 >> 21 1684 | s8 += carry[7] 1685 | s7 -= carry[7] << 21 1686 | carry[8] = s8 >> 21 1687 | s9 += carry[8] 1688 | s8 -= carry[8] << 21 1689 | carry[9] = s9 >> 21 1690 | s10 += carry[9] 1691 | s9 -= carry[9] << 21 1692 | carry[10] = s10 >> 21 1693 | s11 += carry[10] 1694 | s10 -= carry[10] << 21 1695 | carry[11] = s11 >> 21 1696 | s12 += carry[11] 1697 | s11 -= carry[11] << 21 1698 | 1699 | s0 += s12 * 666643 1700 | s1 += s12 * 470296 1701 | s2 += s12 * 654183 1702 | s3 -= s12 * 997805 1703 | s4 += s12 * 136657 1704 | s5 -= s12 * 683901 1705 | s12 = 0 1706 | 1707 | carry[0] = s0 >> 21 1708 | s1 += carry[0] 1709 | s0 -= carry[0] << 21 1710 | carry[1] = s1 >> 21 1711 | s2 += carry[1] 1712 | s1 -= carry[1] << 21 1713 | carry[2] = s2 >> 21 1714 | s3 += carry[2] 1715 | s2 -= carry[2] << 21 1716 | carry[3] = s3 >> 21 1717 | s4 += carry[3] 1718 | s3 -= carry[3] << 21 1719 | carry[4] = s4 >> 21 1720 | s5 += carry[4] 1721 | s4 -= carry[4] << 21 1722 | carry[5] = s5 >> 21 1723 | s6 += carry[5] 1724 | s5 -= carry[5] << 21 1725 | carry[6] = s6 >> 21 1726 | s7 += carry[6] 1727 | s6 -= carry[6] << 21 1728 | carry[7] = s7 >> 21 1729 | s8 += carry[7] 1730 | s7 -= carry[7] << 21 1731 | carry[8] = s8 >> 21 1732 | s9 += carry[8] 1733 | s8 -= carry[8] << 21 1734 | carry[9] = s9 >> 21 1735 | s10 += carry[9] 1736 | s9 -= carry[9] << 21 1737 | carry[10] = s10 >> 21 1738 | s11 += carry[10] 1739 | s10 -= carry[10] << 21 1740 | 1741 | out[0] = byte(s0 >> 0) 1742 | out[1] = byte(s0 >> 8) 1743 | out[2] = byte((s0 >> 16) | (s1 << 5)) 1744 | out[3] = byte(s1 >> 3) 1745 | out[4] = byte(s1 >> 11) 1746 | out[5] = byte((s1 >> 19) | (s2 << 2)) 1747 | out[6] = byte(s2 >> 6) 1748 | out[7] = byte((s2 >> 14) | (s3 << 7)) 1749 | out[8] = byte(s3 >> 1) 1750 | out[9] = byte(s3 >> 9) 1751 | out[10] = byte((s3 >> 17) | (s4 << 4)) 1752 | out[11] = byte(s4 >> 4) 1753 | out[12] = byte(s4 >> 12) 1754 | out[13] = byte((s4 >> 20) | (s5 << 1)) 1755 | out[14] = byte(s5 >> 7) 1756 | out[15] = byte((s5 >> 15) | (s6 << 6)) 1757 | out[16] = byte(s6 >> 2) 1758 | out[17] = byte(s6 >> 10) 1759 | out[18] = byte((s6 >> 18) | (s7 << 3)) 1760 | out[19] = byte(s7 >> 5) 1761 | out[20] = byte(s7 >> 13) 1762 | out[21] = byte(s8 >> 0) 1763 | out[22] = byte(s8 >> 8) 1764 | out[23] = byte((s8 >> 16) | (s9 << 5)) 1765 | out[24] = byte(s9 >> 3) 1766 | out[25] = byte(s9 >> 11) 1767 | out[26] = byte((s9 >> 19) | (s10 << 2)) 1768 | out[27] = byte(s10 >> 6) 1769 | out[28] = byte((s10 >> 14) | (s11 << 7)) 1770 | out[29] = byte(s11 >> 1) 1771 | out[30] = byte(s11 >> 9) 1772 | out[31] = byte(s11 >> 17) 1773 | } 1774 | 1775 | // order is the order of Curve25519 in little-endian form. 1776 | var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} 1777 | 1778 | // ScMinimal returns true if the given scalar is less than the order of the 1779 | // curve. 1780 | func ScMinimal(scalar *[32]byte) bool { 1781 | for i := 3; ; i-- { 1782 | v := binary.LittleEndian.Uint64(scalar[i*8:]) 1783 | if v > order[i] { 1784 | return false 1785 | } else if v < order[i] { 1786 | break 1787 | } else if i == 0 { 1788 | return false 1789 | } 1790 | } 1791 | 1792 | return true 1793 | } 1794 | --------------------------------------------------------------------------------