From fd2a2eba7f0799f762a81ca030c1f7db322520e6 Mon Sep 17 00:00:00 2001 From: Captain Date: Sat, 27 Feb 2021 16:00:43 +0000 Subject: [PATCH] DERO-HE STARGATE Testnet Release13 --- address/LICENSE | 90 -- address/address.go | 187 --- address/address_test.go1 | 250 ---- address/bech32.go | 217 ---- address/bech32_test.go | 402 ------ blockchain/sc.go | 8 +- blockchain/transaction_execute.go | 32 +- blockchain/transaction_verify.go | 18 + cmd/derod/rpc_dero_gettransactions.go | 2 +- config/config.go | 2 +- config/version.go | 2 +- crypto/LICENSE | 90 -- crypto/algebra_elgamal.go | 177 --- crypto/algebra_fieldvector.go | 201 --- crypto/algebra_pedersen.go | 110 -- crypto/algebra_pointvector.go | 192 --- crypto/bn256/CODE_OF_CONDUCT.md | 47 - crypto/bn256/LICENSE | 27 - crypto/bn256/Makefile | 34 - crypto/bn256/README.md | 33 - crypto/bn256/bn256.go | 490 ------- crypto/bn256/bn256_test.go | 116 -- crypto/bn256/constants.go | 79 -- crypto/bn256/curve.go | 318 ----- crypto/bn256/curve_test.go | 66 - crypto/bn256/example_test.go | 51 - crypto/bn256/g1_serialization.go | 424 ------ crypto/bn256/g1_serialization_test.go | 241 ---- crypto/bn256/g2_serialization.go | 266 ---- crypto/bn256/g2_serialization_test.go | 174 --- crypto/bn256/gfp.go | 188 --- crypto/bn256/gfp12.go | 160 --- crypto/bn256/gfp2.go | 327 ----- crypto/bn256/gfp2_test.go | 164 --- crypto/bn256/gfp6.go | 213 ---- crypto/bn256/gfp_amd64.s | 129 -- crypto/bn256/gfp_arm64.s | 113 -- crypto/bn256/gfp_decl.go | 25 - crypto/bn256/gfp_generic.go | 209 --- crypto/bn256/gfp_test.go | 116 -- crypto/bn256/go.mod | 8 - crypto/bn256/go.sum | 9 - crypto/bn256/lattice.go | 115 -- crypto/bn256/lattice_test.go | 29 - crypto/bn256/main_test.go | 71 -- crypto/bn256/mul_amd64.h | 181 --- crypto/bn256/mul_arm64.h | 133 -- crypto/bn256/mul_bmi2_amd64.h | 112 -- crypto/bn256/optate.go | 271 ---- crypto/bn256/twist.go | 217 ---- crypto/bnred.go | 102 -- crypto/const.go | 57 - crypto/fieldvector.go | 297 ----- crypto/generatorparams.go | 72 -- crypto/group.go | 73 -- crypto/hash.go | 65 - crypto/hashtopoint.go | 260 ---- crypto/keccak.go | 41 - crypto/keccak_test.go | 57 - crypto/key_old.go | 70 - crypto/paymentid.go | 59 - crypto/polynomial.go | 91 -- crypto/proof_generate.go | 1206 ------------------ crypto/proof_innerproduct.go | 313 ----- crypto/proof_verify.go | 534 -------- crypto/protocol_structures.go | 189 --- crypto/random.go | 44 - crypto/sha3/doc.go | 66 - crypto/sha3/hashes.go | 97 -- crypto/sha3/hashes_generic.go | 27 - crypto/sha3/keccakf.go | 412 ------ crypto/sha3/keccakf_amd64.go | 13 - crypto/sha3/keccakf_amd64.s | 390 ------ crypto/sha3/register.go | 18 - crypto/sha3/sha3.go | 193 --- crypto/sha3/sha3_s390x.go | 284 ----- crypto/sha3/sha3_s390x.s | 33 - crypto/sha3/sha3_test.go | 483 ------- crypto/sha3/shake.go | 173 --- crypto/sha3/shake_generic.go | 19 - crypto/sha3/testdata/keccakKats.json.deflate | Bin 540828 -> 0 bytes crypto/sha3/xor.go | 23 - crypto/sha3/xor_generic.go | 28 - crypto/sha3/xor_unaligned.go | 65 - p2p/chain_sync.go | 6 +- walletapi/daemon_communication.go | 22 +- 86 files changed, 77 insertions(+), 12941 deletions(-) delete mode 100644 address/LICENSE delete mode 100644 address/address.go delete mode 100644 address/address_test.go1 delete mode 100644 address/bech32.go delete mode 100644 address/bech32_test.go delete mode 100644 crypto/LICENSE delete mode 100644 crypto/algebra_elgamal.go delete mode 100644 crypto/algebra_fieldvector.go delete mode 100644 crypto/algebra_pedersen.go delete mode 100644 crypto/algebra_pointvector.go delete mode 100644 crypto/bn256/CODE_OF_CONDUCT.md delete mode 100644 crypto/bn256/LICENSE delete mode 100644 crypto/bn256/Makefile delete mode 100644 crypto/bn256/README.md delete mode 100644 crypto/bn256/bn256.go delete mode 100644 crypto/bn256/bn256_test.go delete mode 100644 crypto/bn256/constants.go delete mode 100644 crypto/bn256/curve.go delete mode 100644 crypto/bn256/curve_test.go delete mode 100644 crypto/bn256/example_test.go delete mode 100644 crypto/bn256/g1_serialization.go delete mode 100644 crypto/bn256/g1_serialization_test.go delete mode 100644 crypto/bn256/g2_serialization.go delete mode 100644 crypto/bn256/g2_serialization_test.go delete mode 100644 crypto/bn256/gfp.go delete mode 100644 crypto/bn256/gfp12.go delete mode 100644 crypto/bn256/gfp2.go delete mode 100644 crypto/bn256/gfp2_test.go delete mode 100644 crypto/bn256/gfp6.go delete mode 100644 crypto/bn256/gfp_amd64.s delete mode 100644 crypto/bn256/gfp_arm64.s delete mode 100644 crypto/bn256/gfp_decl.go delete mode 100644 crypto/bn256/gfp_generic.go delete mode 100644 crypto/bn256/gfp_test.go delete mode 100644 crypto/bn256/go.mod delete mode 100644 crypto/bn256/go.sum delete mode 100644 crypto/bn256/lattice.go delete mode 100644 crypto/bn256/lattice_test.go delete mode 100644 crypto/bn256/main_test.go delete mode 100644 crypto/bn256/mul_amd64.h delete mode 100644 crypto/bn256/mul_arm64.h delete mode 100644 crypto/bn256/mul_bmi2_amd64.h delete mode 100644 crypto/bn256/optate.go delete mode 100644 crypto/bn256/twist.go delete mode 100644 crypto/bnred.go delete mode 100644 crypto/const.go delete mode 100644 crypto/fieldvector.go delete mode 100644 crypto/generatorparams.go delete mode 100644 crypto/group.go delete mode 100644 crypto/hash.go delete mode 100644 crypto/hashtopoint.go delete mode 100644 crypto/keccak.go delete mode 100644 crypto/keccak_test.go delete mode 100644 crypto/key_old.go delete mode 100644 crypto/paymentid.go delete mode 100644 crypto/polynomial.go delete mode 100644 crypto/proof_generate.go delete mode 100644 crypto/proof_innerproduct.go delete mode 100644 crypto/proof_verify.go delete mode 100644 crypto/protocol_structures.go delete mode 100644 crypto/random.go delete mode 100644 crypto/sha3/doc.go delete mode 100644 crypto/sha3/hashes.go delete mode 100644 crypto/sha3/hashes_generic.go delete mode 100644 crypto/sha3/keccakf.go delete mode 100644 crypto/sha3/keccakf_amd64.go delete mode 100644 crypto/sha3/keccakf_amd64.s delete mode 100644 crypto/sha3/register.go delete mode 100644 crypto/sha3/sha3.go delete mode 100644 crypto/sha3/sha3_s390x.go delete mode 100644 crypto/sha3/sha3_s390x.s delete mode 100644 crypto/sha3/sha3_test.go delete mode 100644 crypto/sha3/shake.go delete mode 100644 crypto/sha3/shake_generic.go delete mode 100644 crypto/sha3/testdata/keccakKats.json.deflate delete mode 100644 crypto/sha3/xor.go delete mode 100644 crypto/sha3/xor_generic.go delete mode 100644 crypto/sha3/xor_unaligned.go diff --git a/address/LICENSE b/address/LICENSE deleted file mode 100644 index 26fca3f..0000000 --- a/address/LICENSE +++ /dev/null @@ -1,90 +0,0 @@ -RESEARCH LICENSE - - -Version 1.1.2 - -I. DEFINITIONS. - -"Licensee " means You and any other party that has entered into and has in effect a version of this License. - -“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees. - -"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology. - -"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage. - -"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License. - -"Technology Site" means the website designated by Licensor for accessing the Technology. - -"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License. - -II. PURPOSE. - -Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology. - -COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT . - -III. RESEARCH USE RIGHTS. - -A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only: - -1. reproduce, create Modifications of, and use the Technology alone, or with Modifications; -2. share source code of the Technology alone, or with Modifications, with other Licensees; - -3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and - -4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology. - -B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights. - -C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License. - -D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution. - -IV. INTELLECTUAL PROPERTY REQUIREMENTS - -As a condition to Your License, You agree to comply with the following restrictions and responsibilities: - -A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology. - -B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License. - -V. GENERAL TERMS. - -A. Disclaimer Of Warranties. - -TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE. - -B. Infringement; Limitation Of Liability. - -1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site. - -2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY. - -C. Termination. - -1. You may terminate this License at any time by notifying Licensor in writing. - -2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance. - -3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination. - -D. Miscellaneous. - -1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor. - -2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof. - -3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate. - -4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter. - -5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications. - -READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING. - -BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. - -IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM. - diff --git a/address/address.go b/address/address.go deleted file mode 100644 index 1692523..0000000 --- a/address/address.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package address - -import "fmt" - -//import "bytes" -//import "encoding/binary" - -//import "github.com/deroproject/derohe/config" -import "github.com/deroproject/derohe/crypto" - -// older dero address https://cryptonote.org/cns/cns007.txt to understand address more -// current dero versions use https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki - -// there are 3 hrps for mainnet DERO, DEROI,DEROPROOF -// these are 3 hrps for testnet DETO, DETOI,DEROPROOF -// so a total of 5 hrps -// 1 byte version is support capable to represent 255 versions, currently we will be using only version 1 -// point is 33 bytes -// payment id if present is 8 bytes - -type Address struct { - Network uint64 - Amount uint64 // integrated address can also contain amount to send - Mainnet bool - Proof bool - PublicKey *crypto.Point //33 byte compressed point - PaymentID []byte //integrated payment id is 8 bytes, It is encrypted on the blockchain -} - -// SegwitAddrEncode encodes hrp(human-readable part) , version(int) and data(bytes array), returns Segwit Address / or error -func (a *Address) DeroAddrEncode() (string, error) { - hrp := "dero" - if !a.Mainnet { - hrp = "deto" - } - - if len(a.PaymentID) == 8 { - hrp += "i" - } - - if a.Proof { - hrp = "deroproof" - } - - // first we are appending version byte - data_bytes := append([]byte{1}, a.PublicKey.EncodeCompressed()...) - data_bytes = append(data_bytes, a.PaymentID...) - var data_ints []int - for i := range data_bytes { - data_ints = append(data_ints, int(data_bytes[i])) - } - - data, err := convertbits(data_ints, 8, 5, true) - if err != nil { - return "", err - } - ret, err := Encode(hrp, data) - if err != nil { - return "", err - } - return ret, nil -} - -// stringifier -func (a Address) String() string { - result, _ := a.DeroAddrEncode() - return result -} - -// split address into parts -func (a Address) Split() (z Address, payment_id []byte) { - z = a - z.PaymentID = []byte{} - if len(z.PaymentID) == 8 { - payment_id = append(payment_id, a.PaymentID...) - } - return z, payment_id -} - -// if address has amount -func (a Address) IntegratedAmount() uint64 { - return a.Amount -} - -func (a Address) Compressed() []byte { - return a.PublicKey.EncodeCompressed() -} - -// tells whether address is mainnet address -func (a *Address) IsMainnet() bool { - return a.Mainnet -} - -// tells whether address is mainnet address -func (a *Address) IsIntegratedAddress() bool { - return len(a.PaymentID) > 0 -} - -// tells whether address belongs to DERO Network -func (a *Address) IsDERONetwork() bool { - return true -} - -// NewAddress decodes hrp(human-readable part) Address(string), returns address or error -func NewAddress(addr string) (result *Address, err error) { - dechrp, data, err := Decode(addr) - if err != nil { - return nil, err - } - result = &Address{PublicKey: new(crypto.Point)} - switch dechrp { - case "dero", "deroi", "deto", "detoi", "deroproof": - default: - return nil, fmt.Errorf("invalid human-readable part : %s != %s", "", dechrp) - } - if len(data) < 1 { - return nil, fmt.Errorf("invalid decode version: %d", len(data)) - } - - res, err := convertbits(data, 5, 8, false) - if err != nil { - return nil, err - } - - if res[0] != 1 { - return nil, fmt.Errorf("invalid address version : %d", res[0]) - } - res = res[1:] - - var resbytes []byte - for _, b := range res { - resbytes = append(resbytes, byte(b)) - } - - if len(resbytes) < 33 { - return nil, fmt.Errorf("invalid address length as per spec : %d", len(res)) - } - - if err = result.PublicKey.DecodeCompressed(resbytes[0:33]); err != nil { - return - } - - result.Mainnet = true - if dechrp == "deto" || dechrp == "detoi" { - result.Mainnet = false - } - if dechrp == "deroproof" { - result.Proof = true - } - - switch { - case len(res) == 33 && (dechrp == "dero" || dechrp == "deto"): - case len(res) == 33+8 && (dechrp == "deroi" || dechrp == "detoi" || dechrp == "deroproof"): // address only has payment id - result.PaymentID = append(result.PaymentID, resbytes[33:33+8]...) - - case len(res) == 33+8+8 && (dechrp == "deroi" || dechrp == "detoi"): // address has payment id and amount support - default: - return nil, fmt.Errorf("invalid address length as per spec : %d", len(res)) - } - - return result, nil -} - -// create a new address from key -func NewAddressFromKeys(key *crypto.Point) (result *Address) { - result = &Address{ - Mainnet: true, - PublicKey: new(crypto.Point).Set(key), - } - return -} diff --git a/address/address_test.go1 b/address/address_test.go1 deleted file mode 100644 index 3377146..0000000 --- a/address/address_test.go1 +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2017-2018 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package address - -import "fmt" -import "bytes" -import "testing" -import "encoding/hex" - -import "github.com/deroproject/derohe/config" - -func TestAddressError(t *testing.T) { - _, err := NewAddress("") - want := fmt.Errorf("Address is not complete") - if err.Error() != want.Error() { - t.Fatalf("want: %s, got: %s", want, err) - } - - _, err = NewAddress("dERoNzsi5WW1ABhQ1UGLwoLqBU6sbzvyuS4cCi4PGzW7QRM5TH4MUf3QvZUBNJCYSDPw6K495eroGe24cf75uDdD2QwWy9pchN") - want = fmt.Errorf("Checksum failed") - if err.Error() != want.Error() { - t.Fatalf("want: %s, got: %s", want, err) - } - -} - -func TestAddress(t *testing.T) { - - const Monero_MainNetwork = 18 - const Monero_TestNetwork = 53 - - tests := []struct { - name string - Network uint64 - SpendingKeyHex string - ViewingKeyHex string - Address string - }{ - { - name: "generic", - Network: Monero_MainNetwork, - SpendingKeyHex: "8c1a9d5ff5aaf1c3cdeb2a1be62f07a34ae6b15fe47a254c8bc240f348271679", - ViewingKeyHex: "0a29b163e392eb9416a52907fd7d3b84530f8d02ff70b1f63e72fdcb54cf7fe1", - Address: "46w3n5EGhBeZkYmKvQRsd8UK9GhvcbYWQDobJape3NLMMFEjFZnJ3CnRmeKspubQGiP8iMTwFEX2QiBsjUkjKT4SSPd3fKp", - }, - { - name: "generic 2", - Network: Monero_MainNetwork, - SpendingKeyHex: "5007b84275af9a173c2080683afce90b2157ab640c18ddd5ce3e060a18a9ce99", - ViewingKeyHex: "27024b45150037b677418fcf11ba9675494ffdf994f329b9f7a8f8402b7934a0", - Address: "44f1Y84r9Lu4tQdLWRxV122rygfhUeVBrcmBaqcYCwUHScmf1ht8DFLXX9YN4T7nPPLcpqYLUdrFiY77nQYeH9RuK9gg4p6", - }, - { - name: "require 1 padding in middle", - Network: Monero_MainNetwork, - SpendingKeyHex: "6add197bd82866e8bfbf1dc2fdf49873ec5f679059652da549cd806f2b166756", - ViewingKeyHex: "f5cf2897088fda0f7ac1c42491ed7d558a46ee41d0c81d038fd53ff4360afda0", - Address: "45fzHekTd5FfvxWBPYX2TqLPbtWjaofxYUeWCi6BRQXYFYd85sY2qw73bAuKhqY7deFJr6pN3STY81bZ9x2Zf4nGKASksqe", - }, - { - name: "require 1 padding in last chunk", - Network: Monero_MainNetwork, - SpendingKeyHex: "50defe92d88b19aaf6bf66f061dd4380b79866a4122b25a03bceb571767dbe7b", - ViewingKeyHex: "f8f6f28283921bf5a17f0bcf4306233fc25ce9b6276154ad0de22aebc5c67702", - Address: "44grjkXtDHJVbZgtU1UKnrNXidcHfZ3HWToU5WjR3KgHMjgwrYLjXC6i5vm3HCp4vnBfYaNEyNiuZVwqtHD2SenS1JBRyco", - }, - { - name: "testnet", - Network: Monero_TestNetwork, - SpendingKeyHex: "8de9cce254e60cd940abf6c77ef344c3a21fad74320e45734fbfcd5870e5c875", - ViewingKeyHex: "27024b45150037b677418fcf11ba9675494ffdf994f329b9f7a8f8402b7934a0", - Address: "9xYZvCDf6aFdLd7Qawg5XHZitWLKoeFvcLHfe5GxsGCFLbXSWeQNKciXX9YN4T7nPPLcpqYLUdrFiY77nQYeH9RuK9bogZJ", - }, - - { - name: "DERO testnet", - Network: config.Testnet.Public_Address_Prefix, - SpendingKeyHex: "ffb4baf32792d38d36c5f1792201d1cff142a10bad6aa088090156a35858739d", - ViewingKeyHex: "0ea428a9608fc9dc06acceea608ac97cc9119647b943941a381306548ee43455", - Address: "dETosYceeTxRZQBk5hQzN51JepzZn5H24JqR96q7mY7ZFo6JhJKPNSKR3vs9ES1ibyQDQgeRheDP6CJbb7AKJY2H9eacz2RtPy", - }, - { - name: "DERO mainnet requires padding in second block", - Network: config.Mainnet.Public_Address_Prefix, - SpendingKeyHex: "10a80329a700f25c9892a696de768f5bdc73cafe6095d647e5707c04f48c0481", - ViewingKeyHex: "b0fa8ca43a8f07681274ddd8fa891aea4222aa8027dd516bc144317a042547c4", - Address: "dERoNzsi5WW1ABhQ1UGLwoLqBU6sbzvyuS4cCi4PGzW7QRM5TH4MUf3QvZUBNJCYSDPw6K495eroGe24cf75uDdD2QwWy9pchM", - }, - } - var base58 string - var spendingKey, viewingKey []byte - for _, test := range tests { - spendingKey, _ = hex.DecodeString(test.SpendingKeyHex) - viewingKey, _ = hex.DecodeString(test.ViewingKeyHex) - - address, err := NewAddress(test.Address) - if err != nil { - t.Fatalf("%s: Failed while parsing address %s", test.name, err) - continue - } - - if address.Network != test.Network { - t.Fatalf("%s: want: %d, got: %d", test.name, test.Network, address.Network) - continue - } - - if bytes.Compare(address.SpendKey[:], spendingKey) != 0 { - t.Fatalf("%s: want: %x, got: %s", test.name, spendingKey, address.SpendKey) - continue - } - if bytes.Compare(address.ViewKey[:], viewingKey) != 0 { - t.Fatalf("%s: want: %x, got: %s", test.name, viewingKey, address.ViewKey) - continue - } - - base58 = address.Base58() - if base58 != test.Address { - t.Fatalf("%s: want: %s, got: %s", test.name, test.Address, base58) - continue - } - - } -} - -// more explaination here https://monero.stackexchange.com/questions/1910/how-do-payment-ids-work -// test case created from here https://xmr.llcoins.net/addresstests.html -func TestIntegratedAddress(t *testing.T) { - - const Monero_MainNetwork = 18 - const Monero_MainNetwork_Integrated = 19 - const Monero_TestNetwork = 53 - - tests := []struct { - name string - Network uint64 - NetworkI uint64 - SpendingKeyHex string - ViewingKeyHex string - PaymentID string - Address string - AddressI string - }{ - { - name: "generic", - Network: Monero_MainNetwork, - NetworkI: Monero_MainNetwork_Integrated, - SpendingKeyHex: "80d3eca27896f549abc41dd941d08a4c82cff165a7f8bc4c3c0841cffd11c095", - ViewingKeyHex: "7849297236cd7c0d6c69a3c8c179c038d3c1c434735741bb3c8995c3c9d6f2ac", - PaymentID: "90470a40196034b5", - Address: "46WGHoGHRT2DKhdr4BxzhXDoFe5NBjNm1Dka5144aXZHS13cAoUQWRq3FE2gcT3LJjAWJ6fGWq8t8YKRqwwit8vmLT6tcxK", - - AddressI: "4GCwJc5n2iYDKhdr4BxzhXDoFe5NBjNm1Dka5144aXZHS13cAoUQWRq3FE2gcT3LJjAWJ6fGWq8t8YKRqwwit8vmVs5oxyLeWQsMWmcgkC", - }, - - { - name: "generic", - Network: config.Mainnet.Public_Address_Prefix, - NetworkI: config.Mainnet.Public_Address_Prefix_Integrated, - SpendingKeyHex: "bd7393b76af23611e6e0eb1e4974bcb5688fceea6ad8a1b08435a4e68fcb7b8c", - ViewingKeyHex: "c828aa405d78c3a0b0a7263d2cb82811d4c6ee3374ada5cc753d8196a271b3d2", - PaymentID: "0cbd6e050cf3b73c", - Address: "dERoiVavtPjhWkdEPp17RJLXVoHkr2ucMdEbgGgpskhLb33732LBifWMCZhPga3EcjXoYqfM9jRv3W3bnWUSpdmK5Jur1PhN6P", - - AddressI: "dERijfr9y7XhWkdEPp17RJLXVoHkr2ucMdEbgGgpskhLb33732LBifWMCZhPga3EcjXoYqfM9jRv3W3bnWUSpdmKL24FBjG6ctTAEg1jrhDHh", - }, - } - - var base58 string - var spendingKey, viewingKey []byte - for _, test := range tests { - spendingKey, _ = hex.DecodeString(test.SpendingKeyHex) - viewingKey, _ = hex.DecodeString(test.ViewingKeyHex) - - address, err := NewAddress(test.Address) - if err != nil { - t.Fatalf("%s: Failed while parsing address %s", test.name, err) - continue - } - - if address.Network != test.Network { - t.Errorf("%s: want: %d, got: %d", test.name, test.Network, address.Network) - continue - } - - if bytes.Compare(address.SpendKey[:], spendingKey) != 0 { - t.Fatalf("%s: want: %x, got: %s", test.name, spendingKey, address.SpendKey) - continue - } - if bytes.Compare(address.ViewKey[:], viewingKey) != 0 { - t.Fatalf("%s: want: %x, got: %s", test.name, viewingKey, address.ViewKey) - continue - } - - base58 = address.Base58() - if base58 != test.Address { - t.Fatalf("%s: want: %s, got: %s", test.name, test.Address, base58) - continue - } - - address, err = NewAddress(test.AddressI) - if err != nil { - t.Fatalf("%s: Failed while parsing address %s", test.name, err) - continue - } - - base58 = address.Base58() - if base58 != test.AddressI { - t.Fatalf("%s: want: %s, got: %s", test.name, test.AddressI, base58) - continue - } - - if fmt.Sprintf("%x", address.PaymentID) != test.PaymentID { - t.Fatalf("%s: PaymentID want: %s, got: %s", test.name, test.PaymentID, address.PaymentID) - } - - } - -} - -func Test_Bruteforce_IntegratedAddress(t *testing.T) { - var AddressI string = "dERijfr9y7XhWkdEPp17RJLXVoHkr2ucMdEbgGgpskhLb33732LBifWMCZhPga3EcjXoYqfM9jRv3W3bnWUSpdmKL24FBjG6ctTAEg1jrhDHh" - - var PaymentID string = "0cbd6e050cf3b73c" - - - for i := 0; i < 100000;i++ { - address, err := NewAddress(AddressI) - if err != nil { - t.Fatalf("%s: Failed while parsing address %s", AddressI, err) - continue - } - if fmt.Sprintf("%x",address.PaymentID) != PaymentID{ - t.Fatalf("Payment ID failed at loop %d", i) - } - } -} diff --git a/address/bech32.go b/address/bech32.go deleted file mode 100644 index c5ea288..0000000 --- a/address/bech32.go +++ /dev/null @@ -1,217 +0,0 @@ -// Package bech32 reference implementation for Bech32 and segwit addresses. -// Copyright (c) 2017 Takatoshi Nakagawa -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -package address - -import ( - "bytes" - "fmt" - "strings" -) - -var charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - -var generator = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} - -func polymod(values []int) int { - chk := 1 - for _, v := range values { - top := chk >> 25 - chk = (chk&0x1ffffff)<<5 ^ v - for i := 0; i < 5; i++ { - if (top>>uint(i))&1 == 1 { - chk ^= generator[i] - } - } - } - return chk -} - -func hrpExpand(hrp string) []int { - ret := []int{} - for _, c := range hrp { - ret = append(ret, int(c>>5)) - } - ret = append(ret, 0) - for _, c := range hrp { - ret = append(ret, int(c&31)) - } - return ret -} - -func verifyChecksum(hrp string, data []int) bool { - return polymod(append(hrpExpand(hrp), data...)) == 1 -} - -func createChecksum(hrp string, data []int) []int { - values := append(append(hrpExpand(hrp), data...), []int{0, 0, 0, 0, 0, 0}...) - mod := polymod(values) ^ 1 - ret := make([]int, 6) - for p := 0; p < len(ret); p++ { - ret[p] = (mod >> uint(5*(5-p))) & 31 - } - return ret -} - -// Encode encodes hrp(human-readable part) and data(32bit data array), returns Bech32 / or error -// if hrp is uppercase, return uppercase Bech32 -func Encode(hrp string, data []int) (string, error) { - if (len(hrp) + len(data) + 7) > 90 { - return "", fmt.Errorf("too long : hrp length=%d, data length=%d", len(hrp), len(data)) - } - if len(hrp) < 1 { - return "", fmt.Errorf("invalid hrp : hrp=%v", hrp) - } - for p, c := range hrp { - if c < 33 || c > 126 { - return "", fmt.Errorf("invalid character human-readable part : hrp[%d]=%d", p, c) - } - } - if strings.ToUpper(hrp) != hrp && strings.ToLower(hrp) != hrp { - return "", fmt.Errorf("mix case : hrp=%v", hrp) - } - lower := strings.ToLower(hrp) == hrp - hrp = strings.ToLower(hrp) - combined := append(data, createChecksum(hrp, data)...) - var ret bytes.Buffer - ret.WriteString(hrp) - ret.WriteString("1") - for idx, p := range combined { - if p < 0 || p >= len(charset) { - return "", fmt.Errorf("invalid data : data[%d]=%d", idx, p) - } - ret.WriteByte(charset[p]) - } - if lower { - return ret.String(), nil - } - return strings.ToUpper(ret.String()), nil -} - -// Decode decodes bechString(Bech32) returns hrp(human-readable part) and data(32bit data array) / or error -func Decode(bechString string) (string, []int, error) { - if len(bechString) > 90 { - return "", nil, fmt.Errorf("too long : len=%d", len(bechString)) - } - if strings.ToLower(bechString) != bechString && strings.ToUpper(bechString) != bechString { - return "", nil, fmt.Errorf("mixed case") - } - bechString = strings.ToLower(bechString) - pos := strings.LastIndex(bechString, "1") - if pos < 1 || pos+7 > len(bechString) { - return "", nil, fmt.Errorf("separator '1' at invalid position : pos=%d , len=%d", pos, len(bechString)) - } - hrp := bechString[0:pos] - for p, c := range hrp { - if c < 33 || c > 126 { - return "", nil, fmt.Errorf("invalid character human-readable part : bechString[%d]=%d", p, c) - } - } - data := []int{} - for p := pos + 1; p < len(bechString); p++ { - d := strings.Index(charset, fmt.Sprintf("%c", bechString[p])) - if d == -1 { - return "", nil, fmt.Errorf("invalid character data part : bechString[%d]=%d", p, bechString[p]) - } - data = append(data, d) - } - if !verifyChecksum(hrp, data) { - return "", nil, fmt.Errorf("invalid checksum") - } - return hrp, data[:len(data)-6], nil -} - -func convertbits(data []int, frombits, tobits uint, pad bool) ([]int, error) { - acc := 0 - bits := uint(0) - ret := []int{} - maxv := (1 << tobits) - 1 - for idx, value := range data { - if value < 0 || (value>>frombits) != 0 { - return nil, fmt.Errorf("invalid data range : data[%d]=%d (frombits=%d)", idx, value, frombits) - } - acc = (acc << frombits) | value - bits += frombits - for bits >= tobits { - bits -= tobits - ret = append(ret, (acc>>bits)&maxv) - } - } - if pad { - if bits > 0 { - ret = append(ret, (acc<<(tobits-bits))&maxv) - } - } else if bits >= frombits { - return nil, fmt.Errorf("illegal zero padding") - } else if ((acc << (tobits - bits)) & maxv) != 0 { - return nil, fmt.Errorf("non-zero padding") - } - return ret, nil -} - -// SegwitAddrDecode decodes hrp(human-readable part) Segwit Address(string), returns version(int) and data(bytes array) / or error -func SegwitAddrDecode(hrp, addr string) (int, []int, error) { - dechrp, data, err := Decode(addr) - if err != nil { - return -1, nil, err - } - if dechrp != hrp { - return -1, nil, fmt.Errorf("invalid human-readable part : %s != %s", hrp, dechrp) - } - if len(data) < 1 { - return -1, nil, fmt.Errorf("invalid decode data length : %d", len(data)) - } - if data[0] > 16 { - return -1, nil, fmt.Errorf("invalid witness version : %d", data[0]) - } - res, err := convertbits(data[1:], 5, 8, false) - if err != nil { - return -1, nil, err - } - if len(res) < 2 || len(res) > 40 { - return -1, nil, fmt.Errorf("invalid convertbits length : %d", len(res)) - } - if data[0] == 0 && len(res) != 20 && len(res) != 32 { - return -1, nil, fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(res)) - } - return data[0], res, nil -} - -// SegwitAddrEncode encodes hrp(human-readable part) , version(int) and data(bytes array), returns Segwit Address / or error -func SegwitAddrEncode(hrp string, version int, program []int) (string, error) { - if version < 0 || version > 16 { - return "", fmt.Errorf("invalid witness version : %d", version) - } - if len(program) < 2 || len(program) > 40 { - return "", fmt.Errorf("invalid program length : %d", len(program)) - } - if version == 0 && len(program) != 20 && len(program) != 32 { - return "", fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(program)) - } - data, err := convertbits(program, 8, 5, true) - if err != nil { - return "", err - } - ret, err := Encode(hrp, append([]int{version}, data...)) - if err != nil { - return "", err - } - return ret, nil -} diff --git a/address/bech32_test.go b/address/bech32_test.go deleted file mode 100644 index 6b34426..0000000 --- a/address/bech32_test.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (c) 2017 Takatoshi Nakagawa -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -package address - -import ( - "reflect" - "strings" - "testing" -) - -func segwitScriptpubkey(version int, program []int) []int { - if version != 0 { - version += 0x50 - } - return append(append([]int{version}, len(program)), program...) -} - -var validChecksum = []string{ - "A12UEL5L", - "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", - "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", - "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", - "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", -} - -var invalidChecksum = []string{ - " 1nwldj5", - "\x7F" + "1axkwrx", - "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", - "pzry9x0s0muk", - "1pzry9x0s0muk", - "x1b4n0q5v", - "li1dgmt3", - "de1lg7wt\xFF", -} - -type item struct { - address string - scriptpubkey []int -} - -var validAddress = []item{ - item{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", - []int{ - 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, - }, - }, - item{"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", - []int{ - 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, - 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, - 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, - 0x62, - }, - }, - item{"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", - []int{ - 0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, - 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, - 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6, - }, - }, - item{"BC1SW50QA3JX3S", - []int{ - 0x60, 0x02, 0x75, 0x1e, - }, - }, - item{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", - []int{ - 0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, - 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, - }, - }, - item{"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", - []int{ - 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, - 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, - 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, - 0x33, - }, - }, -} - -var invalidAddress = []string{ - "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", - "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", - "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", - "bc1rw5uspcuh", - "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", - "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", - "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", - "bc1gmk9yu", -} - -func TestValidChecksum(t *testing.T) { - for _, test := range validChecksum { - hrp, data, err := Decode(test) - if err != nil { - t.Errorf("Valid checksum for %s : FAIL / error %+v\n", test, err) - } else { - t.Logf("Valid checksum for %s : ok / hrp : %+v , data : %+v\n", test, hrp, data) - } - } -} - -func TestInvalidChecksum(t *testing.T) { - for _, test := range invalidChecksum { - hrp, data, err := Decode(test) - if err != nil { - t.Logf("Invalid checksum for %s : ok / hrp : %+v , data : %+v\n", test, hrp, data) - } else { - t.Errorf("Invalid checksum for %s : FAIL\n", test) - } - } -} - -func TestValidAddress(t *testing.T) { - for _, test := range validAddress { - hrp := "bc" - version, program, err := SegwitAddrDecode(hrp, test.address) - if err != nil { - hrp = "tb" - version, program, err = SegwitAddrDecode(hrp, test.address) - } - ok := err == nil - if ok { - output := segwitScriptpubkey(version, program) - ok = reflect.DeepEqual(output, test.scriptpubkey) - } - if ok { - recreate, err := SegwitAddrEncode(hrp, version, program) - if err == nil { - ok = recreate == strings.ToLower(test.address) - } - } - if ok { - t.Logf("Valid address %v : ok\n", test.address) - } else { - t.Errorf("Valid address %v : FAIL\n", test.address) - } - } -} - -func TestInvalidAddress(t *testing.T) { - for _, test := range invalidAddress { - _, _, bcErr := SegwitAddrDecode("bc", test) - t.Logf("bc error:%v\n", bcErr) - _, _, tbErr := SegwitAddrDecode("tb", test) - t.Logf("tb error:%v\n", tbErr) - if bcErr != nil && tbErr != nil { - t.Logf("Invalid address %v : ok\n", test) - } else { - t.Errorf("Invalid address %v : FAIL\n", test) - } - } -} - -// add coverage tests - -func TestCoverage(t *testing.T) { - var err error - var bech32String string - var hrp string - var data []int - - // SegwitAddrEncode - bech32String, err = SegwitAddrEncode("bc", 1, []int{0, 1}) - if err != nil { - t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err) - } else { - t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String) - } - data = make([]int, 40) - bech32String, err = SegwitAddrEncode("bc", 16, data) - if err != nil { - t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err) - } else { - t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String) - } - data = make([]int, 20) - bech32String, err = SegwitAddrEncode("bc", 0, data) - if err != nil { - t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err) - } else { - t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String) - } - data = make([]int, 32) - bech32String, err = SegwitAddrEncode("bc", 0, data) - if err != nil { - t.Errorf("Coverage SegwitAddrEncode normal case : FAIL / error : %+v\n", err) - } else { - t.Log("Coverage SegwitAddrEncode normal case : ok / bech32String :", bech32String) - } - data = make([]int, 1) - _, err = SegwitAddrEncode("bc", 1, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid program length error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid program length error case : ok / error :", err) - } - data = make([]int, 41) - _, err = SegwitAddrEncode("bc", 1, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid program length error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid program length error case : ok / error :", err) - } - data = make([]int, 26) - _, err = SegwitAddrEncode("bc", 0, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid program length for witness version 0 (per BIP141) error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid program length for witness version 0 (per BIP141) error case : ok / error :", err) - } - data = make([]int, 20) - _, err = SegwitAddrEncode("Bc", 0, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode Encode error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode Encode error case : ok / error :", err) - } - _, err = SegwitAddrEncode("bc", 1, []int{-1, 0}) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid data range error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid data range error case : ok / error :", err) - } - _, err = SegwitAddrEncode("bc", -1, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid witness version error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid witness version error case : ok / error :", err) - } - _, err = SegwitAddrEncode("bc", 17, data) - if err == nil { - t.Errorf("Coverage SegwitAddrEncode invalid witness version error case : FAIL") - } else { - t.Log("Coverage SegwitAddrEncode invalid witness version error case : ok / error :", err) - } - - // SegwitAddrDecode - _, _, err = SegwitAddrDecode("a", "A12UEL5L") - if err == nil { - t.Errorf("Coverage SegwitAddrDecode invalid decode data length error case : FAIL") - } else { - t.Log("Coverage SegwitAddrDecode invalid decode data length error case : ok / error :", err) - } - - // Decode - _, _, err = Decode("!~1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc356v3") - if err != nil { - t.Errorf("Coverage Decode normal case : FAIL / error :%v", err) - } else { - t.Log("Coverage Decode normal case : ok") - } - _, _, err = Decode("a1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq") - if err == nil { - t.Errorf("Coverage Decode too long error case : FAIL") - } else { - t.Log("Coverage Decode too long error case : ok / error :", err) - } - _, _, err = Decode("1") - if err == nil { - t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL") - } else { - t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err) - } - _, _, err = Decode("a1qqqqq") - if err == nil { - t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL") - } else { - t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err) - } - _, _, err = Decode("a" + string(rune(32)) + "1qqqqqq") - if err == nil { - t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL") - } else { - t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err) - } - _, _, err = Decode("a" + string(rune(127)) + "1qqqqqq") - if err == nil { - t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL") - } else { - t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err) - } - _, _, err = Decode("a1qqqqqb") - if err == nil { - t.Errorf("Coverage Decode invalid character data part error case : FAIL") - } else { - t.Log("Coverage Decode invalid character data part erroer case : ok / error :", err) - } - - // Encode - hrp = "bc" - data = []int{} - bech32String, err = Encode(hrp, data) - if err != nil || bech32String != strings.ToLower(bech32String) { - t.Errorf("Coverage Encode lower case : FAIL / bech32String : %v , error : %v", bech32String, err) - } else { - t.Log("Coverage Encode lower case : ok / bech32String : ", bech32String) - } - hrp = "BC" - bech32String, err = Encode(hrp, data) - if err != nil || bech32String != strings.ToUpper(bech32String) { - t.Errorf("Coverage Encode upper case : FAIL / bech32String : %v , error : %v", bech32String, err) - } else { - t.Log("Coverage Encode upper case : ok / bech32String : ", bech32String) - } - hrp = "bc" - data = make([]int, 90-7-len(hrp)+1) - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode too long error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode too long error case : ok / error : ", err) - } - hrp = "" - data = make([]int, 90-7-len(hrp)) - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode invalid hrp error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode invalid hrp error case : ok / error : ", err) - } - hrp = "Bc" - data = make([]int, 90-7-len(hrp)) - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode mix case error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode mix case error case : ok / error : ", err) - } - hrp = string(rune(33)) + string(rune(126)) - data = make([]int, 90-7-len(hrp)) - bech32String, err = Encode(hrp, data) - if err != nil { - t.Errorf("Coverage Encode normal case : FAIL / error : %v", err) - } else { - t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String) - } - hrp = string(rune(32)) + "c" - data = make([]int, 90-7-len(hrp)) - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err) - } - hrp = "b" + string(rune(127)) - data = make([]int, 90-7-len(hrp)) - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err) - } - hrp = "bc" - data = []int{0, 31} - bech32String, err = Encode(hrp, data) - if err != nil { - t.Errorf("Coverage Encode normal case : FAIL / error : %v", err) - } else { - t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String) - } - hrp = "bc" - data = []int{-1} - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode invalid data error case : ok / error : ", err) - } - hrp = "bc" - data = []int{32} - bech32String, err = Encode(hrp, data) - if err == nil { - t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String) - } else { - t.Log("Coverage Encode invalid data error case : ok / error : ", err) - } -} diff --git a/blockchain/sc.go b/blockchain/sc.go index 85410bd..38c550d 100644 --- a/blockchain/sc.go +++ b/blockchain/sc.go @@ -73,6 +73,10 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree defer func() { // safety so if anything wrong happens, verification fails if r := recover(); r != nil { + + if err == nil { + err = fmt.Errorf("Stack trace \n%s", debug.Stack()) + } logger.Warnf("Recovered while rewinding chain, Stack trace below block_hash ") logger.Warnf("Stack trace \n%s", debug.Stack()) } @@ -115,13 +119,15 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree balance, sc_parsed, found := chain.ReadSC(w_sc_tree, data_tree, scid) if !found { - fmt.Printf("SC not found\n") + rlog.Warnf("SC not found %s", scid) + err = fmt.Errorf("SC not found %s", scid) return } // if we found the SC in parsed form, check whether entrypoint is found function, ok := sc_parsed.Functions[entrypoint] if !ok { rlog.Warnf("stored SC does not contain entrypoint '%s' scid %s \n", entrypoint, scid) + err = fmt.Errorf("stored SC does not contain entrypoint '%s' scid %s \n", entrypoint, scid) return } _ = function diff --git a/blockchain/transaction_execute.go b/blockchain/transaction_execute.go index 44f351b..6f47e61 100644 --- a/blockchain/transaction_execute.go +++ b/blockchain/transaction_execute.go @@ -25,6 +25,7 @@ import "golang.org/x/xerrors" import "github.com/romana/rlog" import "github.com/deroproject/derohe/cryptography/crypto" +import "github.com/deroproject/derohe/cryptography/bn256" import "github.com/deroproject/derohe/transaction" import "github.com/deroproject/derohe/config" import "github.com/deroproject/derohe/rpc" @@ -134,16 +135,33 @@ func (chain *Blockchain) process_transaction(changed map[crypto.Hash]*graviton.T } for i := 0; i < int(tx.Payloads[t].Statement.RingSize); i++ { key_pointer := tx.Payloads[t].Statement.Publickeylist_pointers[i*int(tx.Payloads[t].Statement.Bytes_per_publickey) : (i+1)*int(tx.Payloads[t].Statement.Bytes_per_publickey)] - if _, key_compressed, balance_serialized, err := tree.GetKeyValueFromHash(key_pointer); err == nil { + _, key_compressed, balance_serialized, err := tree.GetKeyValueFromHash(key_pointer) - balance := new(crypto.ElGamal).Deserialize(balance_serialized) - echanges := crypto.ConstructElGamal(tx.Payloads[t].Statement.C[i], tx.Payloads[t].Statement.D) + if err != nil && !tx.Payloads[t].SCID.IsZero() { + if xerrors.Is(err, graviton.ErrNotFound) { // if the address is not found, lookup in main tree + _, key_compressed, _, err = balance_tree.GetKeyValueFromHash(key_pointer) + if err == nil { + var p bn256.G1 + if err = p.DecodeCompressed(key_compressed[:]); err != nil { + panic(fmt.Errorf("key %d could not be decompressed", i)) + } - balance = balance.Add(echanges) // homomorphic addition of changes - tree.Put(key_compressed, balance.Serialize()) // reserialize and store - } else { - panic(err) // if balance could not be obtained panic ( we can never reach here, otherwise how tx got verified) + balance := crypto.ConstructElGamal(&p, crypto.ElGamal_BASE_G) // init zero balance + balance_serialized = balance.Serialize() + } + + } } + if err != nil { + panic(fmt.Errorf("balance not obtained err %s\n", err)) + } + + balance := new(crypto.ElGamal).Deserialize(balance_serialized) + echanges := crypto.ConstructElGamal(tx.Payloads[t].Statement.C[i], tx.Payloads[t].Statement.D) + + balance = balance.Add(echanges) // homomorphic addition of changes + tree.Put(key_compressed, balance.Serialize()) // reserialize and store + } } diff --git a/blockchain/transaction_verify.go b/blockchain/transaction_verify.go index 86f343b..a62ff01 100644 --- a/blockchain/transaction_verify.go +++ b/blockchain/transaction_verify.go @@ -28,6 +28,7 @@ import "github.com/romana/rlog" import "sync" import "runtime/debug" +import "golang.org/x/xerrors" import "github.com/deroproject/graviton" //import "github.com/romana/rlog" @@ -277,6 +278,18 @@ func (chain *Blockchain) Verify_Transaction_NonCoinbase(hf_version int64, tx *tr for i := 0; i < int(tx.Payloads[t].Statement.RingSize); i++ { key_pointer := tx.Payloads[t].Statement.Publickeylist_pointers[i*int(tx.Payloads[t].Statement.Bytes_per_publickey) : (i+1)*int(tx.Payloads[t].Statement.Bytes_per_publickey)] _, key_compressed, balance_serialized, err := tree.GetKeyValueFromHash(key_pointer) + + // if destination address could be found be found in main balance tree, assume its zero balance + needs_init := false + if err != nil && !tx.Payloads[t].SCID.IsZero() { + if xerrors.Is(err, graviton.ErrNotFound) { // if the address is not found, lookup in main tree + _, key_compressed, _, err = balance_tree.GetKeyValueFromHash(key_pointer) + if err != nil { + return fmt.Errorf("balance not obtained err %s\n", err) + } + needs_init = true + } + } if err != nil { return fmt.Errorf("balance not obtained err %s\n", err) } @@ -291,6 +304,11 @@ func (chain *Blockchain) Verify_Transaction_NonCoinbase(hf_version int64, tx *tr } tx.Payloads[t].Statement.Publickeylist_compressed = append(tx.Payloads[t].Statement.Publickeylist_compressed, pcopy) tx.Payloads[t].Statement.Publickeylist = append(tx.Payloads[t].Statement.Publickeylist, &p) + + if needs_init { + balance := crypto.ConstructElGamal(&p, crypto.ElGamal_BASE_G) // init zero balance + balance_serialized = balance.Serialize() + } } var ll, rr bn256.G1 diff --git a/cmd/derod/rpc_dero_gettransactions.go b/cmd/derod/rpc_dero_gettransactions.go index c0b024e..ac7228b 100644 --- a/cmd/derod/rpc_dero_gettransactions.go +++ b/cmd/derod/rpc_dero_gettransactions.go @@ -188,6 +188,6 @@ func (DERO_RPC_APIS) GetTransaction(ctx context.Context, p rpc.GetTransaction_Pa result.Status = "OK" err = nil - logger.Debugf("result %+v\n", result) + //logger.Debugf("result %+v\n", result) return } diff --git a/config/config.go b/config/config.go index 2aab3d2..4ab82cf 100644 --- a/config/config.go +++ b/config/config.go @@ -104,7 +104,7 @@ var Mainnet = CHAIN_CONFIG{Name: "mainnet", } var Testnet = CHAIN_CONFIG{Name: "testnet", // testnet will always have last 3 bytes 0 - Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x25, 0x00, 0x00, 0x00}), + Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x26, 0x00, 0x00, 0x00}), P2P_Default_Port: 40401, RPC_Default_Port: 40402, Wallet_RPC_Default_Port: 40403, diff --git a/config/version.go b/config/version.go index e8220bb..4dc85c4 100644 --- a/config/version.go +++ b/config/version.go @@ -20,4 +20,4 @@ import "github.com/blang/semver" // right now it has to be manually changed // do we need to include git commitsha?? -var Version = semver.MustParse("3.2.12-1.DEROHE.STARGATE+27022021") +var Version = semver.MustParse("3.2.13-1.DEROHE.STARGATE+27022021") diff --git a/crypto/LICENSE b/crypto/LICENSE deleted file mode 100644 index 26fca3f..0000000 --- a/crypto/LICENSE +++ /dev/null @@ -1,90 +0,0 @@ -RESEARCH LICENSE - - -Version 1.1.2 - -I. DEFINITIONS. - -"Licensee " means You and any other party that has entered into and has in effect a version of this License. - -“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees. - -"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology. - -"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage. - -"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License. - -"Technology Site" means the website designated by Licensor for accessing the Technology. - -"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License. - -II. PURPOSE. - -Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology. - -COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT . - -III. RESEARCH USE RIGHTS. - -A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only: - -1. reproduce, create Modifications of, and use the Technology alone, or with Modifications; -2. share source code of the Technology alone, or with Modifications, with other Licensees; - -3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and - -4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology. - -B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights. - -C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License. - -D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution. - -IV. INTELLECTUAL PROPERTY REQUIREMENTS - -As a condition to Your License, You agree to comply with the following restrictions and responsibilities: - -A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology. - -B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License. - -V. GENERAL TERMS. - -A. Disclaimer Of Warranties. - -TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE. - -B. Infringement; Limitation Of Liability. - -1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site. - -2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY. - -C. Termination. - -1. You may terminate this License at any time by notifying Licensor in writing. - -2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance. - -3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination. - -D. Miscellaneous. - -1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor. - -2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof. - -3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate. - -4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter. - -5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications. - -READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING. - -BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. - -IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM. - diff --git a/crypto/algebra_elgamal.go b/crypto/algebra_elgamal.go deleted file mode 100644 index a618201..0000000 --- a/crypto/algebra_elgamal.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -// a ZERO -var ElGamal_ZERO *bn256.G1 -var ElGamal_ZERO_string string -var ElGamal_BASE_G *bn256.G1 - -type ElGamal struct { - G *bn256.G1 - Randomness *big.Int - Left *bn256.G1 - Right *bn256.G1 -} - -func NewElGamal() (p *ElGamal) { - return &ElGamal{G: global_pedersen_values.G} -} -func CommitElGamal(key *bn256.G1, value *big.Int) *ElGamal { - e := NewElGamal() - e.Randomness = RandomScalarFixed() - e.Left = new(bn256.G1).Add(new(bn256.G1).ScalarMult(e.G, value), new(bn256.G1).ScalarMult(key, e.Randomness)) - e.Right = new(bn256.G1).ScalarMult(G, e.Randomness) - return e -} - -func ConstructElGamal(left, right *bn256.G1) *ElGamal { - e := NewElGamal() - - if left != nil { - e.Left = new(bn256.G1).Set(left) - } - e.Right = new(bn256.G1).Set(right) - return e -} - -func (e *ElGamal) IsZero() bool { - if e.Left != nil && e.Right != nil && e.Left.String() == ElGamal_ZERO_string && e.Right.String() == ElGamal_ZERO_string { - return true - } - return false -} - -func (e *ElGamal) Add(addendum *ElGamal) *ElGamal { - if e.Left == nil { - return ConstructElGamal(nil, new(bn256.G1).Add(e.Right, addendum.Right)) - } - return ConstructElGamal(new(bn256.G1).Add(e.Left, addendum.Left), new(bn256.G1).Add(e.Right, addendum.Right)) -} - -func (e *ElGamal) Mul(scalar *big.Int) *ElGamal { - return ConstructElGamal(new(bn256.G1).ScalarMult(e.Left, scalar), new(bn256.G1).ScalarMult(e.Right, scalar)) -} - -func (e *ElGamal) Plus(value *big.Int) *ElGamal { - if e.Right == nil { - return ConstructElGamal(new(bn256.G1).Add(e.Left, new(bn256.G1).ScalarMult(e.G, value)), nil) - } - return ConstructElGamal(new(bn256.G1).Add(e.Left, new(bn256.G1).ScalarMult(e.G, value)), new(bn256.G1).Set(e.Right)) -} - -func (e *ElGamal) Serialize() (data []byte) { - if e.Left == nil || e.Right == nil { - panic("elgamal has nil pointer") - } - data = append(data, e.Left.EncodeUncompressed()...) - data = append(data, e.Right.EncodeUncompressed()...) - return data -} - -func (e *ElGamal) Deserialize(data []byte) *ElGamal { - - if len(data) != 130 { - panic("insufficient buffer size") - } - //var left,right *bn256.G1 - left := new(bn256.G1) - right := new(bn256.G1) - - if err := left.DecodeUncompressed(data[:65]); err != nil { - panic(err) - } - if err := right.DecodeUncompressed(data[65:130]); err != nil { - panic(err) - } - e = ConstructElGamal(left, right) - return e -} - -func (e *ElGamal) Neg() *ElGamal { - - var left, right *bn256.G1 - if e.Left != nil { - left = new(bn256.G1).Neg(e.Left) - } - if e.Right != nil { - right = new(bn256.G1).Neg(e.Right) - } - return ConstructElGamal(left, right) -} - -type ElGamalVector struct { - vector []*ElGamal -} - -func (e *ElGamalVector) MultiExponentiate(exponents *FieldVector) *ElGamal { - accumulator := ConstructElGamal(ElGamal_ZERO, ElGamal_ZERO) - for i := range exponents.vector { - accumulator = accumulator.Add(e.vector[i].Mul(exponents.vector[i])) - } - return accumulator -} - -func (e *ElGamalVector) Sum() *ElGamal { - r := ConstructElGamal(ElGamal_ZERO, ElGamal_ZERO) - for i := range e.vector { - r = r.Add(e.vector[i]) - } - return r -} - -func (e *ElGamalVector) Add(other *ElGamalVector) *ElGamalVector { - var r ElGamalVector - for i := range e.vector { - r.vector = append(r.vector, ConstructElGamal(e.vector[i].Left, e.vector[i].Right)) - } - - for i := range other.vector { - r.vector[i] = r.vector[i].Add(other.vector[i]) - } - return &r -} - -func (e *ElGamalVector) Hadamard(exponents FieldVector) *ElGamalVector { - var r ElGamalVector - for i := range e.vector { - r.vector = append(r.vector, ConstructElGamal(e.vector[i].Left, e.vector[i].Right)) - } - - for i := range exponents.vector { - r.vector[i] = r.vector[i].Mul(exponents.vector[i]) - } - return &r -} - -func (e *ElGamalVector) Times(scalar *big.Int) *ElGamalVector { - var r ElGamalVector - for i := range e.vector { - r.vector = append(r.vector, e.vector[i].Mul(scalar)) - } - return &r -} diff --git a/crypto/algebra_fieldvector.go b/crypto/algebra_fieldvector.go deleted file mode 100644 index d794f22..0000000 --- a/crypto/algebra_fieldvector.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -type FieldVector struct { - vector []*big.Int -} - -func NewFieldVector(input []*big.Int) *FieldVector { - return &FieldVector{vector: input} -} - -func NewFieldVectorRandomFilled(capacity int) *FieldVector { - fv := &FieldVector{vector: make([]*big.Int, capacity, capacity)} - for i := range fv.vector { - fv.vector[i] = RandomScalarFixed() - } - return fv -} - -func (fv *FieldVector) Length() int { - return len(fv.vector) -} - -// slice and return -func (fv *FieldVector) Slice(start, end int) *FieldVector { - var result FieldVector - for i := start; i < end; i++ { - result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) - } - return &result -} - -//copy and return -func (fv *FieldVector) Clone() *FieldVector { - return fv.Slice(0, len(fv.vector)) -} - -func (fv *FieldVector) SliceRaw(start, end int) []*big.Int { - var result FieldVector - for i := start; i < end; i++ { - result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) - } - return result.vector -} - -func (fv *FieldVector) Flip() *FieldVector { - var result FieldVector - for i := range fv.vector { - result.vector = append(result.vector, new(big.Int).Set(fv.vector[(len(fv.vector)-i)%len(fv.vector)])) - } - return &result -} - -func (fv *FieldVector) Sum() *big.Int { - var accumulator big.Int - - for i := range fv.vector { - var accopy big.Int - - accopy.Add(&accumulator, fv.vector[i]) - accumulator.Mod(&accopy, bn256.Order) - } - - return &accumulator -} - -func (fv *FieldVector) Add(addendum *FieldVector) *FieldVector { - var result FieldVector - - if len(fv.vector) != len(addendum.vector) { - panic("mismatched number of elements") - } - - for i := range fv.vector { - var ri big.Int - ri.Mod(new(big.Int).Add(fv.vector[i], addendum.vector[i]), bn256.Order) - result.vector = append(result.vector, &ri) - } - - return &result -} - -func (gv *FieldVector) AddConstant(c *big.Int) *FieldVector { - var result FieldVector - - for i := range gv.vector { - var ri big.Int - ri.Mod(new(big.Int).Add(gv.vector[i], c), bn256.Order) - result.vector = append(result.vector, &ri) - } - - return &result -} - -func (fv *FieldVector) Hadamard(exponent *FieldVector) *FieldVector { - var result FieldVector - - if len(fv.vector) != len(exponent.vector) { - panic("mismatched number of elements") - } - for i := range fv.vector { - result.vector = append(result.vector, new(big.Int).Mod(new(big.Int).Mul(fv.vector[i], exponent.vector[i]), bn256.Order)) - } - - return &result -} - -func (fv *FieldVector) InnerProduct(exponent *FieldVector) *big.Int { - if len(fv.vector) != len(exponent.vector) { - panic("mismatched number of elements") - } - - accumulator := new(big.Int) - for i := range fv.vector { - tmp := new(big.Int).Mod(new(big.Int).Mul(fv.vector[i], exponent.vector[i]), bn256.Order) - accumulator.Add(accumulator, tmp) - accumulator.Mod(accumulator, bn256.Order) - } - - return accumulator -} - -func (fv *FieldVector) Negate() *FieldVector { - var result FieldVector - for i := range fv.vector { - result.vector = append(result.vector, new(big.Int).Mod(new(big.Int).Neg(fv.vector[i]), bn256.Order)) - } - return &result -} - -func (fv *FieldVector) Times(multiplier *big.Int) *FieldVector { - var result FieldVector - for i := range fv.vector { - res := new(big.Int).Mul(fv.vector[i], multiplier) - res.Mod(res, bn256.Order) - result.vector = append(result.vector, res) - } - return &result -} - -func (fv *FieldVector) Invert() *FieldVector { - var result FieldVector - for i := range fv.vector { - result.vector = append(result.vector, new(big.Int).ModInverse(fv.vector[i], bn256.Order)) - } - return &result -} - -func (fv *FieldVector) Concat(addendum *FieldVector) *FieldVector { - var result FieldVector - for i := range fv.vector { - result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) - } - - for i := range addendum.vector { - result.vector = append(result.vector, new(big.Int).Set(addendum.vector[i])) - } - - return &result -} - -func (fv *FieldVector) Extract(parity bool) *FieldVector { - var result FieldVector - - remainder := 0 - if parity { - remainder = 1 - } - for i := range fv.vector { - if i%2 == remainder { - - result.vector = append(result.vector, new(big.Int).Set(fv.vector[i])) - } - } - return &result -} diff --git a/crypto/algebra_pedersen.go b/crypto/algebra_pedersen.go deleted file mode 100644 index e1244a9..0000000 --- a/crypto/algebra_pedersen.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -var G *bn256.G1 -var global_pedersen_values PedersenVectorCommitment - -func init() { - var zeroes [64]byte - var gs, hs []*bn256.G1 - - global_pedersen_values.G = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "G"))) // this is same as mybase or vice-versa - global_pedersen_values.H = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "H"))) - - global_pedersen_values.GSUM = new(bn256.G1) - global_pedersen_values.GSUM.Unmarshal(zeroes[:]) - - for i := 0; i < 128; i++ { - gs = append(gs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"G"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) - hs = append(hs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"H"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) - - global_pedersen_values.GSUM = new(bn256.G1).Add(global_pedersen_values.GSUM, gs[i]) - } - global_pedersen_values.Gs = NewPointVector(gs) - global_pedersen_values.Hs = NewPointVector(hs) - - // also initialize elgamal_zero - ElGamal_ZERO = new(bn256.G1).ScalarMult(global_pedersen_values.G, new(big.Int).SetUint64(0)) - ElGamal_ZERO_string = ElGamal_ZERO.String() - ElGamal_BASE_G = global_pedersen_values.G - G = global_pedersen_values.G - ((*bn256.G1)(&GPoint)).Set(G) // setup base point - - // fmt.Printf("basepoint %s on %x\n", G.String(), G.Marshal()) -} - -type PedersenCommitmentNew struct { - G *bn256.G1 - H *bn256.G1 - Randomness *big.Int - Result *bn256.G1 -} - -func NewPedersenCommitmentNew() (p *PedersenCommitmentNew) { - return &PedersenCommitmentNew{G: global_pedersen_values.G, H: global_pedersen_values.H} -} - -// commit a specific value to specific bases -func (p *PedersenCommitmentNew) Commit(value *big.Int) *PedersenCommitmentNew { - p.Randomness = RandomScalarFixed() - point := new(bn256.G1).Add(new(bn256.G1).ScalarMult(p.G, value), new(bn256.G1).ScalarMult(p.H, p.Randomness)) - p.Result = new(bn256.G1).Set(point) - return p -} - -type PedersenVectorCommitment struct { - G *bn256.G1 - H *bn256.G1 - GSUM *bn256.G1 - - Gs *PointVector - Hs *PointVector - Randomness *big.Int - Result *bn256.G1 - - gvalues *FieldVector - hvalues *FieldVector -} - -func NewPedersenVectorCommitment() (p *PedersenVectorCommitment) { - p = &PedersenVectorCommitment{} - *p = global_pedersen_values - return -} - -// commit a specific value to specific bases -func (p *PedersenVectorCommitment) Commit(gvalues, hvalues *FieldVector) *PedersenVectorCommitment { - - p.Randomness = RandomScalarFixed() - point := new(bn256.G1).ScalarMult(p.H, p.Randomness) - point = new(bn256.G1).Add(point, p.Gs.MultiExponentiate(gvalues)) - point = new(bn256.G1).Add(point, p.Hs.MultiExponentiate(hvalues)) - - p.Result = new(bn256.G1).Set(point) - return p -} diff --git a/crypto/algebra_pointvector.go b/crypto/algebra_pointvector.go deleted file mode 100644 index 7a5d792..0000000 --- a/crypto/algebra_pointvector.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -// ToDO evaluate others curves such as BLS12 used by zcash, also BLS24 or others , providing ~200 bits of security , may be required for long time use( say 50 years) -type PointVector struct { - vector []*bn256.G1 -} - -func NewPointVector(input []*bn256.G1) *PointVector { - return &PointVector{vector: input} -} - -func (gv *PointVector) Length() int { - return len(gv.vector) -} - -// slice and return -func (gv *PointVector) Slice(start, end int) *PointVector { - var result PointVector - for i := start; i < end; i++ { - var ri bn256.G1 - ri.Set(gv.vector[i]) - result.vector = append(result.vector, &ri) - } - return &result -} - -func (gv *PointVector) Commit(exponent []*big.Int) *bn256.G1 { - var accumulator, zero bn256.G1 - var zeroes [64]byte - accumulator.Unmarshal(zeroes[:]) // obtain zero element, this should be static and - zero.Unmarshal(zeroes[:]) - - accumulator.ScalarMult(G, new(big.Int)) - - //fmt.Printf("zero %s\n", accumulator.String()) - - if len(gv.vector) != len(exponent) { - panic("mismatched number of elements") - } - for i := range gv.vector { // TODO a bug exists somewhere deep here - var tmp, accopy bn256.G1 - tmp.ScalarMult(gv.vector[i], exponent[i]) - - accopy.Set(&accumulator) - accumulator.Add(&accopy, &tmp) - } - - return &accumulator -} - -func (gv *PointVector) Sum() *bn256.G1 { - var accumulator bn256.G1 - - accumulator.ScalarMult(G, new(big.Int)) // set it to zero - - for i := range gv.vector { - var accopy bn256.G1 - - accopy.Set(&accumulator) - accumulator.Add(&accopy, gv.vector[i]) - } - - return &accumulator -} - -func (gv *PointVector) Add(addendum *PointVector) *PointVector { - var result PointVector - - if len(gv.vector) != len(addendum.vector) { - panic("mismatched number of elements") - } - - for i := range gv.vector { - var ri bn256.G1 - - ri.Add(gv.vector[i], addendum.vector[i]) - result.vector = append(result.vector, &ri) - } - - return &result -} - -func (gv *PointVector) Hadamard(exponent []*big.Int) *PointVector { - var result PointVector - - if len(gv.vector) != len(exponent) { - panic("mismatched number of elements") - } - for i := range gv.vector { - var ri bn256.G1 - ri.ScalarMult(gv.vector[i], exponent[i]) - result.vector = append(result.vector, &ri) - - } - - return &result -} - -func (gv *PointVector) Negate() *PointVector { - var result PointVector - for i := range gv.vector { - var ri bn256.G1 - ri.Neg(gv.vector[i]) - result.vector = append(result.vector, &ri) - } - return &result -} - -func (gv *PointVector) Times(multiplier *big.Int) *PointVector { - var result PointVector - for i := range gv.vector { - var ri bn256.G1 - ri.ScalarMult(gv.vector[i], multiplier) - result.vector = append(result.vector, &ri) - } - return &result -} - -func (gv *PointVector) Extract(parity bool) *PointVector { - var result PointVector - - remainder := 0 - if parity { - remainder = 1 - } - for i := range gv.vector { - if i%2 == remainder { - var ri bn256.G1 - ri.Set(gv.vector[i]) - result.vector = append(result.vector, &ri) - } - } - return &result -} - -func (gv *PointVector) Concat(addendum *PointVector) *PointVector { - var result PointVector - for i := range gv.vector { - var ri bn256.G1 - ri.Set(gv.vector[i]) - result.vector = append(result.vector, &ri) - } - - for i := range addendum.vector { - var ri bn256.G1 - ri.Set(addendum.vector[i]) - result.vector = append(result.vector, &ri) - } - - return &result -} - -func (pv *PointVector) MultiExponentiate(fv *FieldVector) *bn256.G1 { - var accumulator bn256.G1 - - accumulator.ScalarMult(G, new(big.Int)) // set it to zero - - for i := range fv.vector { - var accopy bn256.G1 - - accopy.Set(&accumulator) - accumulator.Add(&accopy, new(bn256.G1).ScalarMult(pv.vector[i], fv.vector[i])) - } - - return &accumulator -} diff --git a/crypto/bn256/CODE_OF_CONDUCT.md b/crypto/bn256/CODE_OF_CONDUCT.md deleted file mode 100644 index 61069f8..0000000 --- a/crypto/bn256/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,47 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [opensource@clearmatics.com][email]. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[email]: mailto:opensource@clearmatics.com -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/crypto/bn256/LICENSE b/crypto/bn256/LICENSE deleted file mode 100644 index 6a66aea..0000000 --- a/crypto/bn256/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/crypto/bn256/Makefile b/crypto/bn256/Makefile deleted file mode 100644 index 464399b..0000000 --- a/crypto/bn256/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -SHELL = bash -GO_FILES = $(shell find . -name "*.go" | grep -vE ".git") -GO_COVER_FILE = `find . -name "coverage.out"` - -.PHONY: all test format cover-clean check fmt vet lint - -test: $(GO_FILES) - go test ./... - -format: - gofmt -s -w ${GO_FILES} - -cover: $(GO_FILES) - go test -coverprofile=coverage.out ./... - go tool cover -html=coverage.out - -cover-clean: - rm -f $(GO_COVER_FILE) - -deps: - go mod download - -check: - if [ -n "$(shell gofmt -l ${GO_FILES})" ]; then \ - echo 1>&2 'The following files need to be formatted:'; \ - gofmt -l .; \ - exit 1; \ - fi - -vet: - go vet $(GO_FILES) - -lint: - golint $(GO_FILES) diff --git a/crypto/bn256/README.md b/crypto/bn256/README.md deleted file mode 100644 index e4a77fd..0000000 --- a/crypto/bn256/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# BN256 - -[![Build Status](https://travis-ci.org/clearmatics/bn256.svg?branch=master)](https://travis-ci.org/clearmatics/bn256) - -This package implements a [particular](https://eprint.iacr.org/2013/507.pdf) bilinear group. -The code is imported from https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare - -:rotating_light: **WARNING** This package originally claimed to operate at a 128-bit level. However, [recent work](https://ellipticnews.wordpress.com/2016/05/02/kim-barbulescu-variant-of-the-number-field-sieve-to-compute-discrete-logarithms-in-finite-fields/) suggest that **this is no longer the case**. - -## A note on the selection of the bilinear group - -The parameters defined in the `constants.go` file follow the parameters used in [alt-bn128 (libff)](https://github.com/scipr-lab/libff/blob/master/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp). These parameters were selected so that `r−1` has a high 2-adic order. This is key to improve efficiency of the key and proof generation algorithms of the SNARK used. - -## Installation - - go get github.com/clearmatics/bn256 - -## Development - -This project uses [go modules](https://github.com/golang/go/wiki/Modules). -If you develop in your `GOPATH` and use GO 1.11, make sure to run: -```bash -export GO111MODULE=on -``` - -In fact: -> (Inside $GOPATH/src, for compatibility, the go command still runs in the old GOPATH mode, even if a go.mod is found.) -See: https://blog.golang.org/using-go-modules - -> For more fine-grained control, the module support in Go 1.11 respects a temporary environment variable, GO111MODULE, which can be set to one of three string values: off, on, or auto (the default). If GO111MODULE=off, then the go command never uses the new module support. Instead it looks in vendor directories and GOPATH to find dependencies; we now refer to this as "GOPATH mode." If GO111MODULE=on, then the go command requires the use of modules, never consulting GOPATH. We refer to this as the command being module-aware or running in "module-aware mode". If GO111MODULE=auto or is unset, then the go command enables or disables module support based on the current directory. Module support is enabled only when the current directory is outside GOPATH/src and itself contains a go.mod file or is below a directory containing a go.mod file. -See: https://golang.org/cmd/go/#hdr-Preliminary_module_support - -The project follows standard Go conventions using `gofmt`. If you wish to contribute to the project please follow standard Go conventions. The CI server automatically runs these checks. diff --git a/crypto/bn256/bn256.go b/crypto/bn256/bn256.go deleted file mode 100644 index ff58584..0000000 --- a/crypto/bn256/bn256.go +++ /dev/null @@ -1,490 +0,0 @@ -// Package bn256 implements a particular bilinear group at the 128-bit security -// level. -// -// Bilinear groups are the basis of many of the new cryptographic protocols that -// have been proposed over the past decade. They consist of a triplet of groups -// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ -// is a generator of the respective group). That function is called a pairing -// function. -// -// This package specifically implements the Optimal Ate pairing over a 256-bit -// Barreto-Naehrig curve as described in -// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible -// with the implementation described in that paper. -package bn256 - -import ( - "crypto/rand" - "errors" - "io" - "math/big" -) - -func randomK(r io.Reader) (k *big.Int, err error) { - for { - k, err = rand.Int(r, Order) - if k.Sign() > 0 || err != nil { - return - } - } -} - -// G1 is an abstract cyclic group. The zero value is suitable for use as the -// output of an operation, but cannot be used as an input. -type G1 struct { - p *curvePoint -} - -// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. -func RandomG1(r io.Reader) (*big.Int, *G1, error) { - k, err := randomK(r) - if err != nil { - return nil, nil, err - } - - return k, new(G1).ScalarBaseMult(k), nil -} - -func (e *G1) String() string { - return "bn256.G1" + e.p.String() -} - -// ScalarBaseMult sets e to g*k where g is the generator of the group and then -// returns e. -func (e *G1) ScalarBaseMult(k *big.Int) *G1 { - if e.p == nil { - e.p = &curvePoint{} - } - e.p.Mul(curveGen, k) - return e -} - -// ScalarMult sets e to a*k and then returns e. -func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { - if e.p == nil { - e.p = &curvePoint{} - } - e.p.Mul(a.p, k) - return e -} - -// Add sets e to a+b and then returns e. -func (e *G1) Add(a, b *G1) *G1 { - if e.p == nil { - e.p = &curvePoint{} - } - e.p.Add(a.p, b.p) - return e -} - -// Neg sets e to -a and then returns e. -func (e *G1) Neg(a *G1) *G1 { - if e.p == nil { - e.p = &curvePoint{} - } - e.p.Neg(a.p) - return e -} - -// Set sets e to a and then returns e. -func (e *G1) Set(a *G1) *G1 { - if e.p == nil { - e.p = &curvePoint{} - } - e.p.Set(a.p) - return e -} - -// Marshal converts e to a byte slice. -func (e *G1) Marshal() []byte { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - - if e.p == nil { - e.p = &curvePoint{} - } - - e.p.MakeAffine() - ret := make([]byte, numBytes*2) - if e.p.IsInfinity() { - return ret - } - temp := &gfP{} - - montDecode(temp, &e.p.x) - temp.Marshal(ret) - montDecode(temp, &e.p.y) - temp.Marshal(ret[numBytes:]) - - return ret -} - -// Unmarshal sets e to the result of converting the output of Marshal back into -// a group element and then returns e. -func (e *G1) Unmarshal(m []byte) ([]byte, error) { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - if len(m) < 2*numBytes { - return nil, errors.New("bn256: not enough data") - } - // Unmarshal the points and check their caps - if e.p == nil { - e.p = &curvePoint{} - } else { - e.p.x, e.p.y = gfP{0}, gfP{0} - } - var err error - if err = e.p.x.Unmarshal(m); err != nil { - return nil, err - } - if err = e.p.y.Unmarshal(m[numBytes:]); err != nil { - return nil, err - } - // Encode into Montgomery form and ensure it's on the curve - montEncode(&e.p.x, &e.p.x) - montEncode(&e.p.y, &e.p.y) - - zero := gfP{0} - if e.p.x == zero && e.p.y == zero { - // This is the point at infinity. - e.p.y = *newGFp(1) - e.p.z = gfP{0} - e.p.t = gfP{0} - } else { - e.p.z = *newGFp(1) - e.p.t = *newGFp(1) - - if !e.p.IsOnCurve() { - return nil, errors.New("bn256: malformed point") - } - } - return m[2*numBytes:], nil -} - -// G2 is an abstract cyclic group. The zero value is suitable for use as the -// output of an operation, but cannot be used as an input. -type G2 struct { - p *twistPoint -} - -// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r. -func RandomG2(r io.Reader) (*big.Int, *G2, error) { - k, err := randomK(r) - if err != nil { - return nil, nil, err - } - - return k, new(G2).ScalarBaseMult(k), nil -} - -func (e *G2) String() string { - return "bn256.G2" + e.p.String() -} - -// ScalarBaseMult sets e to g*k where g is the generator of the group and then -// returns out. -func (e *G2) ScalarBaseMult(k *big.Int) *G2 { - if e.p == nil { - e.p = &twistPoint{} - } - e.p.Mul(twistGen, k) - return e -} - -// ScalarMult sets e to a*k and then returns e. -func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { - if e.p == nil { - e.p = &twistPoint{} - } - e.p.Mul(a.p, k) - return e -} - -// Add sets e to a+b and then returns e. -func (e *G2) Add(a, b *G2) *G2 { - if e.p == nil { - e.p = &twistPoint{} - } - e.p.Add(a.p, b.p) - return e -} - -// Neg sets e to -a and then returns e. -func (e *G2) Neg(a *G2) *G2 { - if e.p == nil { - e.p = &twistPoint{} - } - e.p.Neg(a.p) - return e -} - -// Set sets e to a and then returns e. -func (e *G2) Set(a *G2) *G2 { - if e.p == nil { - e.p = &twistPoint{} - } - e.p.Set(a.p) - return e -} - -// Marshal converts e into a byte slice. -func (e *G2) Marshal() []byte { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - - if e.p == nil { - e.p = &twistPoint{} - } - - e.p.MakeAffine() - ret := make([]byte, numBytes*4) - if e.p.IsInfinity() { - return ret - } - temp := &gfP{} - - montDecode(temp, &e.p.x.x) - temp.Marshal(ret) - montDecode(temp, &e.p.x.y) - temp.Marshal(ret[numBytes:]) - montDecode(temp, &e.p.y.x) - temp.Marshal(ret[2*numBytes:]) - montDecode(temp, &e.p.y.y) - temp.Marshal(ret[3*numBytes:]) - - return ret -} - -// Unmarshal sets e to the result of converting the output of Marshal back into -// a group element and then returns e. -func (e *G2) Unmarshal(m []byte) ([]byte, error) { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - if len(m) < 4*numBytes { - return nil, errors.New("bn256: not enough data") - } - // Unmarshal the points and check their caps - if e.p == nil { - e.p = &twistPoint{} - } - var err error - if err = e.p.x.x.Unmarshal(m); err != nil { - return nil, err - } - if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil { - return nil, err - } - // Encode into Montgomery form and ensure it's on the curve - montEncode(&e.p.x.x, &e.p.x.x) - montEncode(&e.p.x.y, &e.p.x.y) - montEncode(&e.p.y.x, &e.p.y.x) - montEncode(&e.p.y.y, &e.p.y.y) - - if e.p.x.IsZero() && e.p.y.IsZero() { - // This is the point at infinity. - e.p.y.SetOne() - e.p.z.SetZero() - e.p.t.SetZero() - } else { - e.p.z.SetOne() - e.p.t.SetOne() - - if !e.p.IsOnCurve() { - return nil, errors.New("bn256: malformed point") - } - } - return m[4*numBytes:], nil -} - -// GT is an abstract cyclic group. The zero value is suitable for use as the -// output of an operation, but cannot be used as an input. -type GT struct { - p *gfP12 -} - -// Pair calculates an Optimal Ate pairing. -func Pair(g1 *G1, g2 *G2) *GT { - return >{optimalAte(g2.p, g1.p)} -} - -// PairingCheck calculates the Optimal Ate pairing for a set of points. -func PairingCheck(a []*G1, b []*G2) bool { - acc := new(gfP12) - acc.SetOne() - - for i := 0; i < len(a); i++ { - if a[i].p.IsInfinity() || b[i].p.IsInfinity() { - continue - } - acc.Mul(acc, miller(b[i].p, a[i].p)) - } - return finalExponentiation(acc).IsOne() -} - -// Miller applies Miller's algorithm, which is a bilinear function from the -// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1, -// g2). -func Miller(g1 *G1, g2 *G2) *GT { - return >{miller(g2.p, g1.p)} -} - -func (e *GT) String() string { - return "bn256.GT" + e.p.String() -} - -// ScalarMult sets e to a*k and then returns e. -func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { - if e.p == nil { - e.p = &gfP12{} - } - e.p.Exp(a.p, k) - return e -} - -// Add sets e to a+b and then returns e. -func (e *GT) Add(a, b *GT) *GT { - if e.p == nil { - e.p = &gfP12{} - } - e.p.Mul(a.p, b.p) - return e -} - -// Neg sets e to -a and then returns e. -func (e *GT) Neg(a *GT) *GT { - if e.p == nil { - e.p = &gfP12{} - } - e.p.Conjugate(a.p) - return e -} - -// Set sets e to a and then returns e. -func (e *GT) Set(a *GT) *GT { - if e.p == nil { - e.p = &gfP12{} - } - e.p.Set(a.p) - return e -} - -// Finalize is a linear function from F_p^12 to GT. -func (e *GT) Finalize() *GT { - ret := finalExponentiation(e.p) - e.p.Set(ret) - return e -} - -// Marshal converts e into a byte slice. -func (e *GT) Marshal() []byte { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - - if e.p == nil { - e.p = &gfP12{} - e.p.SetOne() - } - - ret := make([]byte, numBytes*12) - temp := &gfP{} - - montDecode(temp, &e.p.x.x.x) - temp.Marshal(ret) - montDecode(temp, &e.p.x.x.y) - temp.Marshal(ret[numBytes:]) - montDecode(temp, &e.p.x.y.x) - temp.Marshal(ret[2*numBytes:]) - montDecode(temp, &e.p.x.y.y) - temp.Marshal(ret[3*numBytes:]) - montDecode(temp, &e.p.x.z.x) - temp.Marshal(ret[4*numBytes:]) - montDecode(temp, &e.p.x.z.y) - temp.Marshal(ret[5*numBytes:]) - montDecode(temp, &e.p.y.x.x) - temp.Marshal(ret[6*numBytes:]) - montDecode(temp, &e.p.y.x.y) - temp.Marshal(ret[7*numBytes:]) - montDecode(temp, &e.p.y.y.x) - temp.Marshal(ret[8*numBytes:]) - montDecode(temp, &e.p.y.y.y) - temp.Marshal(ret[9*numBytes:]) - montDecode(temp, &e.p.y.z.x) - temp.Marshal(ret[10*numBytes:]) - montDecode(temp, &e.p.y.z.y) - temp.Marshal(ret[11*numBytes:]) - - return ret -} - -// Unmarshal sets e to the result of converting the output of Marshal back into -// a group element and then returns e. -func (e *GT) Unmarshal(m []byte) ([]byte, error) { - // Each value is a 256-bit number. - const numBytes = 256 / 8 - - if len(m) < 12*numBytes { - return nil, errors.New("bn256: not enough data") - } - - if e.p == nil { - e.p = &gfP12{} - } - - var err error - if err = e.p.x.x.x.Unmarshal(m); err != nil { - return nil, err - } - if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil { - return nil, err - } - if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil { - return nil, err - } - if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil { - return nil, err - } - if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil { - return nil, err - } - if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil { - return nil, err - } - if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil { - return nil, err - } - montEncode(&e.p.x.x.x, &e.p.x.x.x) - montEncode(&e.p.x.x.y, &e.p.x.x.y) - montEncode(&e.p.x.y.x, &e.p.x.y.x) - montEncode(&e.p.x.y.y, &e.p.x.y.y) - montEncode(&e.p.x.z.x, &e.p.x.z.x) - montEncode(&e.p.x.z.y, &e.p.x.z.y) - montEncode(&e.p.y.x.x, &e.p.y.x.x) - montEncode(&e.p.y.x.y, &e.p.y.x.y) - montEncode(&e.p.y.y.x, &e.p.y.y.x) - montEncode(&e.p.y.y.y, &e.p.y.y.y) - montEncode(&e.p.y.z.x, &e.p.y.z.x) - montEncode(&e.p.y.z.y, &e.p.y.z.y) - - return m[12*numBytes:], nil -} diff --git a/crypto/bn256/bn256_test.go b/crypto/bn256/bn256_test.go deleted file mode 100644 index 0c8016d..0000000 --- a/crypto/bn256/bn256_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package bn256 - -import ( - "bytes" - "crypto/rand" - "testing" -) - -func TestG1Marshal(t *testing.T) { - _, Ga, err := RandomG1(rand.Reader) - if err != nil { - t.Fatal(err) - } - ma := Ga.Marshal() - - Gb := new(G1) - _, err = Gb.Unmarshal(ma) - if err != nil { - t.Fatal(err) - } - mb := Gb.Marshal() - - if !bytes.Equal(ma, mb) { - t.Fatal("bytes are different") - } -} - -func TestG2Marshal(t *testing.T) { - _, Ga, err := RandomG2(rand.Reader) - if err != nil { - t.Fatal(err) - } - ma := Ga.Marshal() - - Gb := new(G2) - _, err = Gb.Unmarshal(ma) - if err != nil { - t.Fatal(err) - } - mb := Gb.Marshal() - - if !bytes.Equal(ma, mb) { - t.Fatal("bytes are different") - } -} - -func TestBilinearity(t *testing.T) { - for i := 0; i < 2; i++ { - a, p1, _ := RandomG1(rand.Reader) - b, p2, _ := RandomG2(rand.Reader) - e1 := Pair(p1, p2) - - e2 := Pair(&G1{curveGen}, &G2{twistGen}) - e2.ScalarMult(e2, a) - e2.ScalarMult(e2, b) - - if *e1.p != *e2.p { - t.Fatalf("bad pairing result: %s", e1) - } - } -} - -func TestTripartiteDiffieHellman(t *testing.T) { - a, _ := rand.Int(rand.Reader, Order) - b, _ := rand.Int(rand.Reader, Order) - c, _ := rand.Int(rand.Reader, Order) - - pa, pb, pc := new(G1), new(G1), new(G1) - qa, qb, qc := new(G2), new(G2), new(G2) - - pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) - qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) - pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) - qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) - pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) - qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) - - k1 := Pair(pb, qc) - k1.ScalarMult(k1, a) - k1Bytes := k1.Marshal() - - k2 := Pair(pc, qa) - k2.ScalarMult(k2, b) - k2Bytes := k2.Marshal() - - k3 := Pair(pa, qb) - k3.ScalarMult(k3, c) - k3Bytes := k3.Marshal() - - if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) { - t.Errorf("keys didn't agree") - } -} - -func BenchmarkG1(b *testing.B) { - x, _ := rand.Int(rand.Reader, Order) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - new(G1).ScalarBaseMult(x) - } -} - -func BenchmarkG2(b *testing.B) { - x, _ := rand.Int(rand.Reader, Order) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - new(G2).ScalarBaseMult(x) - } -} -func BenchmarkPairing(b *testing.B) { - for i := 0; i < b.N; i++ { - Pair(&G1{curveGen}, &G2{twistGen}) - } -} diff --git a/crypto/bn256/constants.go b/crypto/bn256/constants.go deleted file mode 100644 index 08cfc8d..0000000 --- a/crypto/bn256/constants.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bn256 - -import ( - "math/big" -) - -func bigFromBase10(s string) *big.Int { - n, _ := new(big.Int).SetString(s, 10) - return n -} - -// u is the BN parameter. -var u = bigFromBase10("4965661367192848881") - -// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. -var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") - -// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. -var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583") - -// p2 is p, represented as little-endian 64-bit words. -var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} - -// np is the negative inverse of p, mod 2^256. -var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b} - -// -// p = 21888242871839275222246405745257275088696311157297823662689037894645226208583; Fp = GF(p) -// r = Fp(2^256) # 6350874878119819312338956282401532409788428879151445726012394534686998597021 -// rInv = 1/r # 20988524275117001072002809824448087578619730785600314334253784976379291040311 -// hex(20988524275117001072002809824448087578619730785600314334253784976379291040311) -// # 2e67157159e5c639 cf63e9cfb74492d9 eb2022850278edf8 ed84884a014afa37 -// <\sage> -// -// rN1 is R^-1 where R = 2^256 mod p. -var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639} - -// -// r2 = r^2 # 3096616502983703923843567936837374451735540968419076528771170197431451843209 -// hex(3096616502983703923843567936837374451735540968419076528771170197431451843209) -// # 06d89f71cab8351f 47ab1eff0a417ff6 b5e71911d44501fb f32cfc5b538afa89 -// <\sage> -// -// r2 is R^2 where R = 2^256 mod p. -var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f} - -// r3 is R^3 where R = 2^256 mod p. -var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544} - -// -// xiToPMinus1Over6 = Fp2(i + 9) ^ ((p-1)/6); xiToPMinus1Over6 -// # 16469823323077808223889137241176536799009286646108169935659301613961712198316*i + 8376118865763821496583973867626364092589906065868298776909617916018768340080 -// <\sage> -// -// The value of `xiToPMinus1Over6` below is the same as the one obtained in sage, but where every field element is montgomery encoded -// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9. -var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}} - -// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9. -var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}} - -// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9. -var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}} - -// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9. -var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0} - -// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p). -var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943} - -// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p). -var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6} - -// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9. -var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}} diff --git a/crypto/bn256/curve.go b/crypto/bn256/curve.go deleted file mode 100644 index d017915..0000000 --- a/crypto/bn256/curve.go +++ /dev/null @@ -1,318 +0,0 @@ -package bn256 - -import ( - "math/big" -) - -// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian -// form and t=z² when valid. G₁ is the set of points of this curve on GF(p). -type curvePoint struct { - x, y, z, t gfP -} - -var curveB = newGFp(3) - -// curveGen is the generator of G₁. -var curveGen = &curvePoint{ - x: *newGFp(1), - y: *newGFp(2), - z: *newGFp(1), - t: *newGFp(1), -} - -func (c *curvePoint) String() string { - c.MakeAffine() - x, y := &gfP{}, &gfP{} - montDecode(x, &c.x) - montDecode(y, &c.y) - return "(" + x.String() + ", " + y.String() + ")" -} - -func (c *curvePoint) Set(a *curvePoint) { - c.x.Set(&a.x) - c.y.Set(&a.y) - c.z.Set(&a.z) - c.t.Set(&a.t) -} - -// IsOnCurve returns true iff c is on the curve. -func (c *curvePoint) IsOnCurve() bool { - c.MakeAffine() - if c.IsInfinity() { - return true - } - - y2, x3 := &gfP{}, &gfP{} - gfpMul(y2, &c.y, &c.y) - gfpMul(x3, &c.x, &c.x) - gfpMul(x3, x3, &c.x) - gfpAdd(x3, x3, curveB) - - return *y2 == *x3 -} - -func (c *curvePoint) SetInfinity() { - c.x = gfP{0} - c.y = *newGFp(1) - c.z = gfP{0} - c.t = gfP{0} -} - -func (c *curvePoint) IsInfinity() bool { - return c.z == gfP{0} -} - -func (c *curvePoint) Add(a, b *curvePoint) { - if a.IsInfinity() { - c.Set(b) - return - } - if b.IsInfinity() { - c.Set(a) - return - } - - // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 - - // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] - // by [u1:s1:z1·z2] and [u2:s2:z1·z2] - // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ - z12, z22 := &gfP{}, &gfP{} - gfpMul(z12, &a.z, &a.z) - gfpMul(z22, &b.z, &b.z) - - u1, u2 := &gfP{}, &gfP{} - gfpMul(u1, &a.x, z22) - gfpMul(u2, &b.x, z12) - - t, s1 := &gfP{}, &gfP{} - gfpMul(t, &b.z, z22) - gfpMul(s1, &a.y, t) - - s2 := &gfP{} - gfpMul(t, &a.z, z12) - gfpMul(s2, &b.y, t) - - // Compute x = (2h)²(s²-u1-u2) - // where s = (s2-s1)/(u2-u1) is the slope of the line through - // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. - // This is also: - // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) - // = r² - j - 2v - // with the notations below. - h := &gfP{} - gfpSub(h, u2, u1) - xEqual := *h == gfP{0} - - gfpAdd(t, h, h) - // i = 4h² - i := &gfP{} - gfpMul(i, t, t) - // j = 4h³ - j := &gfP{} - gfpMul(j, h, i) - - gfpSub(t, s2, s1) - yEqual := *t == gfP{0} - if xEqual && yEqual { - c.Double(a) - return - } - r := &gfP{} - gfpAdd(r, t, t) - - v := &gfP{} - gfpMul(v, u1, i) - - // t4 = 4(s2-s1)² - t4, t6 := &gfP{}, &gfP{} - gfpMul(t4, r, r) - gfpAdd(t, v, v) - gfpSub(t6, t4, j) - - gfpSub(&c.x, t6, t) - - // Set y = -(2h)³(s1 + s*(x/4h²-u1)) - // This is also - // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j - gfpSub(t, v, &c.x) // t7 - gfpMul(t4, s1, j) // t8 - gfpAdd(t6, t4, t4) // t9 - gfpMul(t4, r, t) // t10 - gfpSub(&c.y, t4, t6) - - // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 - gfpAdd(t, &a.z, &b.z) // t11 - gfpMul(t4, t, t) // t12 - gfpSub(t, t4, z12) // t13 - gfpSub(t4, t, z22) // t14 - gfpMul(&c.z, t4, h) -} - -func (c *curvePoint) Double(a *curvePoint) { - // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 - A, B, C := &gfP{}, &gfP{}, &gfP{} - gfpMul(A, &a.x, &a.x) - gfpMul(B, &a.y, &a.y) - gfpMul(C, B, B) - - t, t2 := &gfP{}, &gfP{} - gfpAdd(t, &a.x, B) - gfpMul(t2, t, t) - gfpSub(t, t2, A) - gfpSub(t2, t, C) - - d, e, f := &gfP{}, &gfP{}, &gfP{} - gfpAdd(d, t2, t2) - gfpAdd(t, A, A) - gfpAdd(e, t, A) - gfpMul(f, e, e) - - gfpAdd(t, d, d) - gfpSub(&c.x, f, t) - - gfpAdd(t, C, C) - gfpAdd(t2, t, t) - gfpAdd(t, t2, t2) - gfpSub(&c.y, d, &c.x) - gfpMul(t2, e, &c.y) - gfpSub(&c.y, t2, t) - - gfpMul(t, &a.y, &a.z) - gfpAdd(&c.z, t, t) -} - -func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) { - precomp := [1 << 2]*curvePoint{nil, {}, {}, {}} - precomp[1].Set(a) - precomp[2].Set(a) - gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3) - precomp[3].Add(precomp[1], precomp[2]) - - multiScalar := curveLattice.Multi(scalar) - - sum := &curvePoint{} - sum.SetInfinity() - t := &curvePoint{} - - for i := len(multiScalar) - 1; i >= 0; i-- { - t.Double(sum) - if multiScalar[i] == 0 { - sum.Set(t) - } else { - sum.Add(t, precomp[multiScalar[i]]) - } - } - c.Set(sum) -} - -// Transforms Jacobian coordinates to Affine coordinates -// (X' : Y' : Z) -> (X'/(Z^2) : Y'/(Z^3) : 1) -func (c *curvePoint) MakeAffine() { - // point0 := *newGFp(0) - // point1 := *newGFp(1) - - if c.z == point1 { - return - } else if c.z == point0 { // return point at infinity if z = 0 - c.x = gfP{0} - c.y = point1 - c.t = gfP{0} - return - } - - zInv := &gfP{} - zInv.Invert(&c.z) - - t, zInv2 := &gfP{}, &gfP{} - gfpMul(t, &c.y, zInv) // t = y/z - gfpMul(zInv2, zInv, zInv) // zInv2 = 1/(z^2) - - gfpMul(&c.x, &c.x, zInv2) // x = x/(z^2) - gfpMul(&c.y, t, zInv2) // y = y/(z^3) - - c.z = point1 - c.t = point1 -} - -func (c *curvePoint) Neg(a *curvePoint) { - c.x.Set(&a.x) - gfpNeg(&c.y, &a.y) - c.z.Set(&a.z) - c.t = gfP{0} -} - -var point0 = *newGFp(0) -var point1 = *newGFp(1) - -// this will do batch inversions and thus optimize lookup table generation -// Montgomery Batch Inversion based trick -type G1Array []*G1 - -func (points G1Array) MakeAffine() { - // point0 := *newGFp(0) - // point1 := *newGFp(1) - - accum := newGFp(1) - - var scratch_backup [256]gfP - - var scratch []gfP - if len(points) <= 256 { - scratch = scratch_backup[:0] // avoid allocation is possible - } - for _, e := range points { - if e.p == nil { - e.p = &curvePoint{} - } - scratch = append(scratch, *accum) - if e.p.z == point1 { - continue - } else if e.p.z == point0 { // return point at infinity if z = 0 - e.p.x = gfP{0} - e.p.y = point1 - e.p.t = gfP{0} - continue - } - - gfpMul(accum, accum, &e.p.z) // accum *= z - - /* - zInv := &gfP{} - zInv.Invert(&e.p.z) - fmt.Printf("%d inv %s\n",i, zInv) - */ - } - - zInv_accum := gfP{} - zInv_accum.Invert(accum) - - tmp := gfP{} - zInv := &gfP{} - - for i := len(points) - 1; i >= 0; i-- { - e := points[i] - - if e.p.z == point1 { - continue - } else if e.p.z == point0 { // return point at infinity if z = 0 - continue - } - - tmp = gfP{} - gfpMul(&tmp, &zInv_accum, &e.p.z) - gfpMul(zInv, &zInv_accum, &scratch[i]) - zInv_accum = tmp - // fmt.Printf("%d inv %s\n",i, zInv) - - t, zInv2 := &gfP{}, &gfP{} - gfpMul(t, &e.p.y, zInv) // t = y/z - gfpMul(zInv2, zInv, zInv) // zInv2 = 1/(z^2) - - gfpMul(&e.p.x, &e.p.x, zInv2) // x = x/(z^2) - gfpMul(&e.p.y, t, zInv2) // y = y/(z^3) - - e.p.z = point1 - e.p.t = point1 - } -} diff --git a/crypto/bn256/curve_test.go b/crypto/bn256/curve_test.go deleted file mode 100644 index 3f4f884..0000000 --- a/crypto/bn256/curve_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bn256 - -import ( - "crypto/rand" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestG1Array(t *testing.T) { - count := 8 - - var g1array G1Array - var g1array_opt G1Array - - for i := 0; i < count; i++ { - a, _ := rand.Int(rand.Reader, Order) - g1array = append(g1array, new(G1).ScalarBaseMult(a)) - g1array_opt = append(g1array_opt, new(G1).ScalarBaseMult(a)) - } - g1array_opt.MakeAffine() - for i := range g1array_opt { - require.Equal(t, g1array_opt[i].p.z, *newGFp(1)) // current we are not testing points of infinity - } -} - -func benchmarksingleinverts(count int, b *testing.B) { - var g1array, g1backup G1Array - - for i := 0; i < count; i++ { - a, _ := rand.Int(rand.Reader, Order) - g1backup = append(g1backup, new(G1).ScalarBaseMult(a)) - } - - for n := 0; n < b.N; n++ { - g1array = g1array[:0] - for i := range g1backup { - g1array = append(g1array, new(G1).Set(g1backup[i])) - g1array[i].p.MakeAffine() - } - } -} - -func benchmarkbatchedinverts(count int, b *testing.B) { - var g1array, g1backup G1Array - - for i := 0; i < count; i++ { - a, _ := rand.Int(rand.Reader, Order) - g1backup = append(g1backup, new(G1).ScalarBaseMult(a)) - } - - for n := 0; n < b.N; n++ { - g1array = g1array[:0] - for i := range g1backup { - g1array = append(g1array, new(G1).Set(g1backup[i])) - } - g1array.MakeAffine() - } -} - -func BenchmarkInverts_Single_256(b *testing.B) { benchmarksingleinverts(256, b) } -func BenchmarkInverts_Batched_256(b *testing.B) { benchmarkbatchedinverts(256, b) } diff --git a/crypto/bn256/example_test.go b/crypto/bn256/example_test.go deleted file mode 100644 index 6c28599..0000000 --- a/crypto/bn256/example_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bn256 - -import ( - "crypto/rand" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestExamplePair(t *testing.T) { - // This implements the tripartite Diffie-Hellman algorithm from "A One - // Round Protocol for Tripartite Diffie-Hellman", A. Joux. - // http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf - - // Each of three parties, a, b and c, generate a private value. - a, _ := rand.Int(rand.Reader, Order) - b, _ := rand.Int(rand.Reader, Order) - c, _ := rand.Int(rand.Reader, Order) - - // Then each party calculates g₁ and g₂ times their private value. - pa := new(G1).ScalarBaseMult(a) - qa := new(G2).ScalarBaseMult(a) - - pb := new(G1).ScalarBaseMult(b) - qb := new(G2).ScalarBaseMult(b) - - pc := new(G1).ScalarBaseMult(c) - qc := new(G2).ScalarBaseMult(c) - - // Now each party exchanges its public values with the other two and - // all parties can calculate the shared key. - k1 := Pair(pb, qc) - k1.ScalarMult(k1, a) - - k2 := Pair(pc, qa) - k2.ScalarMult(k2, b) - - k3 := Pair(pa, qb) - k3.ScalarMult(k3, c) - - // k1, k2 and k3 will all be equal. - - require.Equal(t, k1, k2) - require.Equal(t, k1, k3) - - require.Equal(t, len(np), 4) //Avoid gometalinter varcheck err on np -} diff --git a/crypto/bn256/g1_serialization.go b/crypto/bn256/g1_serialization.go deleted file mode 100644 index c508984..0000000 --- a/crypto/bn256/g1_serialization.go +++ /dev/null @@ -1,424 +0,0 @@ -// Package bn256 implements a particular bilinear group at the 128-bit security -// level. -// -// Bilinear groups are the basis of many of the new cryptographic protocols that -// have been proposed over the past decade. They consist of a triplet of groups -// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ -// is a generator of the respective group). That function is called a pairing -// function. -// -// This package specifically implements the Optimal Ate pairing over a 256-bit -// Barreto-Naehrig curve as described in -// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible -// with the implementation described in that paper. -package bn256 - -// This file implement some util functions for the MPC -// especially the serialization and deserialization functions for points in G1 -import ( - "errors" - "math/big" -) - -// Constants related to the bn256 pairing friendly curve -const ( - FqElementSize = 32 - G1CompressedSize = FqElementSize + 1 // + 1 accounts for the additional byte used for masking - G1UncompressedSize = 2*FqElementSize + 1 // + 1 accounts for the additional byte used for masking -) - -// https://github.com/ebfull/pairing/tree/master/src/bls12_381#serialization -// Bytes used to detect the formatting. By reading the first byte of the encoded point we can know it's nature -// ie: we can know if the point is the point at infinity, if it is encoded uncompressed or if it is encoded compressed -// Bit masking used to detect the serialization of the points and their nature -// -// The BSL12-381 curve is built over a 381-bit prime field. -// Thus each point coordinate is represented over 381 bits = 47bytes + 5bits -// Thus, to represent a point we need to have 48bytes, but the last 3 bits of the 48th byte will be set to 0 -// These are these bits that are used to implement the masking, hence why the masking proposed by ebfull was: -const ( - serializationMask = (1 << 5) - 1 // 0001 1111 // Enable to pick the 3 MSB corresponding to the serialization flag - serializationCompressed = 1 << 7 // 1000 0000 - serializationInfinity = 1 << 6 // 0100 0000 - serializationBigY = 1 << 5 // 0010 0000 -) - -// IsHigherY is used to distinguish between the 2 points of E -// that have the same x-coordinate -// The point e is assumed to be given in the affine form -func (e *G1) IsHigherY() bool { - // Check nil pointers - if e.p == nil { - e.p = &curvePoint{} - } - - var yCoord gfP - //yCoord.Set(&e.p.y) - yCoord = e.p.y - - var yCoordNeg gfP - gfpNeg(&yCoordNeg, &yCoord) - - res := gfpCmp(&yCoord, &yCoordNeg) - if res == 1 { // yCoord > yCoordNeg - return true - } else if res == -1 { - return false - } - - return false -} - -// EncodeCompressed converts the compressed point e into bytes -// This function takes a point in the Jacobian form -// This function does not modify the point e -// (the variable `temp` is introduced to avoid to modify e) -func (e *G1) EncodeCompressed() []byte { - // Check nil pointers - if e.p == nil { - e.p = &curvePoint{} - } - - e.p.MakeAffine() - ret := make([]byte, G1CompressedSize) - - // Flag the encoding with the compressed flag - ret[0] |= serializationCompressed - - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return ret - } - - if e.IsHigherY() { - // Flag the encoding with the bigY flag - ret[0] |= serializationBigY - } - - // We start the serializagtion of the coordinates at the index 1 - // Since the index 0 in the `ret` corresponds to the masking - temp := &gfP{} - montDecode(temp, &e.p.x) - temp.Marshal(ret[1:]) - - return ret -} - -// returns to buffer rather than allocation from GC -func (e *G1) EncodeCompressedToBuf(ret []byte) { - // Check nil pointers - if e.p == nil { - e.p = &curvePoint{} - } - - e.p.MakeAffine() - //ret := make([]byte, G1CompressedSize) - - // Flag the encoding with the compressed flag - ret[0] |= serializationCompressed - - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return - } - - if e.IsHigherY() { - // Flag the encoding with the bigY flag - ret[0] |= serializationBigY - } - - // We start the serializagtion of the coordinates at the index 1 - // Since the index 0 in the `ret` corresponds to the masking - temp := &gfP{} - montDecode(temp, &e.p.x) - temp.Marshal(ret[1:]) - - return -} - -// EncodeUncompressed converts the compressed point e into bytes -// Take a point P in Jacobian form (where each coordinate is MontEncoded) -// and encodes it by going back to affine coordinates and montDecode all coordinates -// This function does not modify the point e -// (the variable `temp` is introduced to avoid to modify e) -/* -func (e *G1) EncodeUncompressed() []byte { - // Check nil pointers - if e.p == nil { - e.p = &curvePoint{} - } - - e.p.MakeAffine() - ret := make([]byte, G1UncompressedSize) - - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return ret - } - - // We start the serialization of the coordinates at the index 1 - // Since the index 0 in the `ret` corresponds to the masking - temp := &gfP{} - montDecode(temp, &e.p.x) // Store the montgomery decoding in temp - temp.Marshal(ret[1:33]) // Write temp in the `ret` slice, this is the x-coordinate - montDecode(temp, &e.p.y) - temp.Marshal(ret[33:]) // this is the y-coordinate - - return ret -} -*/ -func (e *G1) EncodeUncompressed() []byte { - // Check nil pointers - if e.p == nil { - e.p = &curvePoint{} - } - - // Set the right flags - ret := make([]byte, G1UncompressedSize) - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return ret - } - - // Marshal - marshal := e.Marshal() - // The encoding = flags || marshalledPoint - copy(ret[1:], marshal) - - return ret -} - -// Takes a MontEncoded x and finds the corresponding y (one of the two possible y's) -func getYFromMontEncodedX(x *gfP) (*gfP, error) { - // Check nil pointers - if x == nil { - return nil, errors.New("Cannot retrieve the y-coordinate form a nil pointer") - } - - // Operations on montgomery encoded field elements - x2 := &gfP{} - gfpMul(x2, x, x) - - x3 := &gfP{} - gfpMul(x3, x2, x) - - rhs := &gfP{} - gfpAdd(rhs, x3, curveB) // curveB is MontEncoded, since it is create with newGFp - - // Montgomery decode rhs - // Needed because when we create a GFp element - // with gfP{}, then it is not montEncoded. However - // if we create an element of GFp by using `newGFp()` - // then this field element is Montgomery encoded - // Above, we have been working on Montgomery encoded field elements - // here we solve the quad. resid. over F (not encoded) - // and then we encode back and return the encoded result - // - // Eg: - // - Px := &gfP{1} => 0000000000000000000000000000000000000000000000000000000000000001 - // - PxNew := newGFp(1) => 0e0a77c19a07df2f666ea36f7879462c0a78eb28f5c70b3dd35d438dc58f0d9d - montDecode(rhs, rhs) - rhsBig, err := rhs.gFpToBigInt() - if err != nil { - return nil, err - } - - // Note, if we use the ModSqrt method, we don't need the exponent, so we can comment these lines - yCoord := big.NewInt(0) - res := yCoord.ModSqrt(rhsBig, P) - if res == nil { - return nil, errors.New("not a square mod P") - } - - yCoordGFp := newGFpFromBigInt(yCoord) - montEncode(yCoordGFp, yCoordGFp) - - return yCoordGFp, nil -} - -// DecodeCompressed decodes a point in the compressed form -// Take a point P encoded (ie: written in affine form where each coordinate is MontDecoded) -// and encodes it by going back to Jacobian coordinates and montEncode all coordinates -func (e *G1) DecodeCompressed(encoding []byte) error { - if len(encoding) != G1CompressedSize { - return errors.New("wrong encoded point size") - } - if encoding[0]&serializationCompressed == 0 { // Also test the length of the encoding to make sure it is 33bytes - return errors.New("point isn't compressed") - } - - // Unmarshal the points and check their caps - if e.p == nil { - e.p = &curvePoint{} - } - { - e.p.x, e.p.y = gfP{0}, gfP{0} - e.p.z, e.p.t = *newGFp(1), *newGFp(1) - } - - // Removes the bits of the masking (This does a bitwise AND with `0001 1111`) - // And thus removes the first 3 bits corresponding to the masking - bin := make([]byte, G1CompressedSize) - copy(bin, encoding) - bin[0] &= serializationMask - - // Decode the point at infinity in the compressed form - if encoding[0]&serializationInfinity != 0 { - if encoding[0]&serializationBigY != 0 { - return errors.New("high Y bit improperly set") - } - - // Similar to `for i:=0; i 0 { // GaNeg.p.y > Ga.p.y - assert.True(t, GaNeg.IsHigherY(), "GaNeg.IsHigherY should be true if GaNeg.p.y > Ga.p.y") - // Test the comparision of the big int also, should be the same result - assert.Equal(t, GaNegYBig.Cmp(GaYBig), 1, "GaNegYBig should be bigger than GaYBig") - } else if res < 0 { // GaNeg.p.y < Ga.p.y - assert.False(t, GaNeg.IsHigherY(), "GaNeg.IsHigherY should be false if GaNeg.p.y < Ga.p.y") - // Test the comparision of the big int also, should be the same result - assert.Equal(t, GaYBig.Cmp(GaNegYBig), 1, "GaYBig should be bigger than GaNegYBig") - } -} - -func TestGetYFromMontEncodedX(t *testing.T) { - // We know that the generator of the curve is P = (x: 1, y: 2, z: 1, t: 1) - // We take x = 1 and we see if we retrieve P such that y = 2 or -P such that y' = Inv(2) - - // Create the GFp element 1 and MontEncode it - PxMontEncoded := newGFp(1) - yRetrieved, err := getYFromMontEncodedX(PxMontEncoded) - assert.Nil(t, err) - - smallYMontEncoded := newGFp(2) - bigYMontEncoded := &gfP{} - gfpNeg(bigYMontEncoded, smallYMontEncoded) - - testCondition := (*yRetrieved == *smallYMontEncoded) || (*yRetrieved == *bigYMontEncoded) - assert.True(t, testCondition, "The retrieved Y should either equal 2 or Inv(2)") -} - -func TestEncodeUncompressed(t *testing.T) { - // Case1: Create random point (Jacobian form) - _, GaInit, err := RandomG1(rand.Reader) - if err != nil { - t.Fatal(err) - } - - // Affine form of GaInit - GaAffine := new(G1) - GaAffine.Set(GaInit) - GaAffine.p.MakeAffine() - - // Encode GaCopy1 with the EncodeUncompress function - GaCopy1 := new(G1) - GaCopy1.Set(GaInit) - encoded := GaCopy1.EncodeUncompressed() - - // Encode GaCopy2 with the Marshal function - GaCopy2 := new(G1) - GaCopy2.Set(GaInit) - marshalled := GaCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! - - // Make sure that the x-coordinate is encoded as it is when we call the Marshal function - assert.Equal( - t, - encoded[1:], // Ignore the masking byte - marshalled[:], - "The EncodeUncompressed and Marshal function yield different results") - - // Unmarshal the point Ga with the unmarshal function - Gb1 := new(G1) - _, err = Gb1.Unmarshal(marshalled) - assert.Nil(t, err) - assert.Equal(t, GaAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") - assert.Equal(t, GaAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") - - // Decode the point Ga with the decodeUncompress function - Gb2 := new(G1) - err = Gb2.DecodeUncompressed(encoded) - assert.Nil(t, err) - assert.Equal(t, GaAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decoded point should equal the x-coord of the intial point") - assert.Equal(t, GaAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decoded point should equal the y-coord of the intial point") - - // Case2: Encode the point at infinity - GInfinity := new(G1) - GInfinity.p = &curvePoint{} - GInfinity.p.SetInfinity() - - // Get the point in affine form - GInfinityAffine := new(G1) - GInfinityAffine.Set(GInfinity) - GInfinityAffine.p.MakeAffine() - - // Encode GaCopy1 with the EncodeUncompress function - GInfinityCopy1 := new(G1) - GInfinityCopy1.Set(GInfinity) - encoded = GInfinityCopy1.EncodeUncompressed() - - // Encode GaCopy2 with the Marshal function - GInfinityCopy2 := new(G1) - GInfinityCopy2.Set(GInfinity) - marshalled = GInfinityCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! - - // Make sure that the x-coordinate is encoded as it is when we call the Marshal function - assert.Equal( - t, - encoded[1:], // Ignore the masking byte - marshalled[:], - "The EncodeUncompressed and Marshal function yield different results") - - // Unmarshal the point Ga with the unmarshal function - Gb1 = new(G1) - _, err = Gb1.Unmarshal(marshalled) - assert.Nil(t, err) - assert.Equal(t, GInfinityAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") - assert.Equal(t, GInfinityAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") - - // Decode the point Ga with the decodeCompress function - Gb2 = new(G1) - err = Gb2.DecodeUncompressed(encoded) - assert.Nil(t, err) - assert.Equal(t, GInfinityAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decompressed point should equal the x-coord of the intial point") - assert.Equal(t, GInfinityAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed point should equal the y-coord of the intial point") -} diff --git a/crypto/bn256/g2_serialization.go b/crypto/bn256/g2_serialization.go deleted file mode 100644 index b020933..0000000 --- a/crypto/bn256/g2_serialization.go +++ /dev/null @@ -1,266 +0,0 @@ -// Package bn256 implements a particular bilinear group at the 128-bit security -// level. -// -// Bilinear groups are the basis of many of the new cryptographic protocols that -// have been proposed over the past decade. They consist of a triplet of groups -// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ -// is a generator of the respective group). That function is called a pairing -// function. -// -// This package specifically implements the Optimal Ate pairing over a 256-bit -// Barreto-Naehrig curve as described in -// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible -// with the implementation described in that paper. -package bn256 - -import ( - "errors" -) - -// This file implement some util functions for the MPC -// especially the serialization and deserialization functions for points in G1 - -// Constants related to the bn256 pairing friendly curve -const ( - Fq2ElementSize = 2 * FqElementSize - G2CompressedSize = Fq2ElementSize + 1 // + 1 accounts for the additional byte used for masking - G2UncompressedSize = 2*Fq2ElementSize + 1 // + 1 accounts for the additional byte used for masking -) - -// EncodeUncompressed converts the compressed point e into bytes -// Take a point P in Jacobian form (where each coordinate is MontEncoded) -// and encodes it by going back to affine coordinates and montDecode all coordinates -// This function does not modify the point e -// (the variable `temp` is introduced to avoid to modify e) -func (e *G2) EncodeUncompressed() []byte { - // Check nil pointers - if e.p == nil { - e.p = &twistPoint{} - } - - // Set the right flags - ret := make([]byte, G2UncompressedSize) - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return ret - } - - // Marshal - marshal := e.Marshal() - // The encoding = flags || marshalledPoint - copy(ret[1:], marshal) - - return ret -} - -// DecodeUncompressed decodes a point in the uncompressed form -// Take a point P encoded (ie: written in affine form where each coordinate is MontDecoded) -// and encodes it by going back to Jacobian coordinates and montEncode all coordinates -func (e *G2) DecodeUncompressed(encoding []byte) error { - if len(encoding) != G2UncompressedSize { - return errors.New("wrong encoded point size") - } - if encoding[0]&serializationCompressed != 0 { // Also test the length of the encoding to make sure it is 65bytes - return errors.New("point is compressed") - } - if encoding[0]&serializationBigY != 0 { // Also test that the bigY flag if not set - return errors.New("bigY flag should not be set") - } - - // Unmarshal the points and check their caps - if e.p == nil { - e.p = &twistPoint{} - } - - // Removes the bits of the masking (This does a bitwise AND with `0001 1111`) - // And thus removes the first 3 bits corresponding to the masking - // Useless for now because in bn256, we added a full byte to enable masking - // However, this is needed if we work over BLS12 and its underlying field - bin := make([]byte, G2UncompressedSize) - copy(bin, encoding) - bin[0] &= serializationMask - - // Decode the point at infinity in the compressed form - if encoding[0]&serializationInfinity != 0 { - // Makes sense to check that all bytes of bin are 0x0 since we removed the masking above} - for i := range bin { - if bin[i] != 0 { - return errors.New("invalid infinity encoding") - } - } - e.p.SetInfinity() - return nil - } - - // We remove the flags and unmarshal the data - _, err := e.Unmarshal(encoding[1:]) - return err -} - -func (e *G2) IsHigherY() bool { - // Check nil pointers - if e.p == nil { - e.p = &twistPoint{} - e.p.MakeAffine() - } - - // Note: the structures attributes are quite confusing here - // In fact, each element of Fp2 is a polynomial with 2 terms - // the `x` and `y` denote these coefficients, ie: xi + y - // However, `x` and `y` are also used to denote the x and y **coordinates** - // of an elliptic curve point. Hence, e.p.y represents the y-coordinate of the - // point e, and e.p.y.y represents the **coefficient** y of the y-coordinate - // of the elliptic curve point e. - // - // TODO: Rename the coefficients of the elements of Fp2 as c0 and c1 to clarify the code - yCoordY := &gfP{} - yCoordY.Set(&e.p.y.y) - yCoordYNeg := &gfP{} - gfpNeg(yCoordYNeg, yCoordY) - - res := gfpCmp(yCoordY, yCoordYNeg) - if res == 1 { // yCoordY > yCoordNegY - return true - } else if res == -1 { - return false - } - - return false -} - -func (e *G2) EncodeCompressed() []byte { - // Check nil pointers - if e.p == nil { - e.p = &twistPoint{} - } - - e.p.MakeAffine() - ret := make([]byte, G2CompressedSize) - - // Flag the encoding with the compressed flag - ret[0] |= serializationCompressed - - if e.p.IsInfinity() { - // Flag the encoding with the infinity flag - ret[0] |= serializationInfinity - return ret - } - - if e.IsHigherY() { - // Flag the encoding with the bigY flag - ret[0] |= serializationBigY - } - - // We start the serialization of the coordinates at the index 1 - // Since the index 0 in the `ret` corresponds to the masking - // - // `temp` contains the the x-coordinate of the point - // Thus, to fully encode `temp`, we need to Marshal it's x coefficient and y coefficient - temp := gfP2Decode(&e.p.x) - temp.x.Marshal(ret[1:]) - temp.y.Marshal(ret[FqElementSize+1:]) - - return ret -} - -// Takes a MontEncoded x and finds the corresponding y (one of the two possible y's) -func getYFromMontEncodedXG2(x *gfP2) (*gfP2, error) { - // Check nil pointers - if x == nil { - return nil, errors.New("Cannot retrieve the y-coordinate from a nil pointer") - } - - x2 := new(gfP2).Mul(x, x) - x3 := new(gfP2).Mul(x2, x) - rhs := new(gfP2).Add(x3, twistB) // twistB is MontEncoded, since it is create with newGFp - - yCoord, err := rhs.Sqrt() - if err != nil { - return nil, err - } - - return yCoord, nil -} - -// DecodeCompressed decodes a point in the compressed form -// Take a point P in G2 decoded (ie: written in affine form where each coordinate is MontDecoded) -// and encodes it by going back to Jacobian coordinates and montEncode all coordinates -func (e *G2) DecodeCompressed(encoding []byte) error { - if len(encoding) != G2CompressedSize { - return errors.New("wrong encoded point size") - } - if encoding[0]&serializationCompressed == 0 { // Also test the length of the encoding to make sure it is 33bytes - return errors.New("point isn't compressed") - } - - // Unmarshal the points and check their caps - if e.p == nil { - e.p = &twistPoint{} - } else { - e.p.x.SetZero() - e.p.y.SetZero() - e.p.z.SetOne() - e.p.t.SetOne() - } - - // Removes the bits of the masking (This does a bitwise AND with `0001 1111`) - // And thus removes the first 3 bits corresponding to the masking - bin := make([]byte, G2CompressedSize) - copy(bin, encoding) - bin[0] &= serializationMask - - // Decode the point at infinity in the compressed form - if encoding[0]&serializationInfinity != 0 { - if encoding[0]&serializationBigY != 0 { - return errors.New("high Y bit improperly set") - } - - // Similar to `for i:=0; i= 0 { - out = &gfP{uint64(x)} - } else { - out = &gfP{uint64(-x)} - gfpNeg(out, out) - } - - montEncode(out, out) - return out -} - -func (e *gfP) String() string { - return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0]) -} - -/* -func byteToUint64(in []byte) (uint64, error) { - if len(in) > 8 { - return 0, errors.New("the input bytes length should be equal to 8 (or smaller)") - } - - // Takes the bytes in the little endian order - // The byte 0x64 translate in a uint64 of the shape 0x64 (= 0x0000000000000064) rather than 0x6400000000000000 - res := binary.LittleEndian.Uint64(in) - return res, nil -} -*/ - -// Makes sure that the -func padBytes(bb []byte) ([]byte, error) { - if len(bb) > 32 { - return []byte{}, errors.New("Cannot pad the given byte slice as the length exceed the padding length") - } - - if len(bb) == 32 { - return bb, nil - } - - padSlice := make([]byte, 32) - index := len(padSlice) - len(bb) - copy(padSlice[index:], bb) - return padSlice, nil -} - -// Convert a big.Int into gfP -func newGFpFromBigInt(in *big.Int) (out *gfP) { - // in >= P, so we mod it to get back in the field - // (ie: we get the smallest representative of the equivalence class mod P) - if res := in.Cmp(P); res >= 0 { - // We need to mod P to get back into the field - in.Mod(in, P) - } - - inBytes := in.Bytes() - // We want to work on byte slices of length 32 to re-assemble our GFpe element - if len(inBytes) < 32 { - // Safe to ignore the err as we are in the if so the condition is satisfied - inBytes, _ = padBytes(inBytes) - } - - out = &gfP{} - var n uint64 - // Now we have the guarantee that inBytes has length 32 so it makes sense to run this for - // loop safely (we won't exceed the boundaries of the container) - for i := 0; i < FpUint64Size; i++ { - buf := bytes.NewBuffer(inBytes[i*8 : (i+1)*8]) - binary.Read(buf, binary.BigEndian, &n) - out[(FpUint64Size-1)-i] = n // In gfP field elements are represented as little-endian 64-bit words - } - - return out -} - -// Returns a new element of GFp montgomery encoded -func newMontEncodedGFpFromBigInt(in *big.Int) *gfP { - res := newGFpFromBigInt(in) - montEncode(res, res) - - return res -} - -// Convert a gfP into a big.Int -func (e *gfP) gFpToBigInt() (*big.Int, error) { - str := e.String() - - out := new(big.Int) - _, ok := out.SetString(str, 16) - if !ok { - return nil, errors.New("couldn't create big.Int from gfP element") - } - - return out, nil -} - -func (e *gfP) Set(f *gfP) { - e[0] = f[0] - e[1] = f[1] - e[2] = f[2] - e[3] = f[3] -} - -func (e *gfP) Invert(f *gfP) { - bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} - - sum, power := &gfP{}, &gfP{} - sum.Set(rN1) - power.Set(f) - - for word := 0; word < 4; word++ { - for bit := uint(0); bit < 64; bit++ { - if (bits[word]>>bit)&1 == 1 { - gfpMul(sum, sum, power) - } - gfpMul(power, power, power) - } - } - - gfpMul(sum, sum, r3) - e.Set(sum) -} - -func (e *gfP) Marshal(out []byte) { - for w := uint(0); w < 4; w++ { - for b := uint(0); b < 8; b++ { - out[8*w+b] = byte(e[3-w] >> (56 - 8*b)) - } - } -} - -func (e *gfP) Unmarshal(in []byte) error { - // Unmarshal the bytes into little endian form - for w := uint(0); w < 4; w++ { - for b := uint(0); b < 8; b++ { - e[3-w] += uint64(in[8*w+b]) << (56 - 8*b) - } - } - // Ensure the point respects the curve modulus - for i := 3; i >= 0; i-- { - if e[i] < p2[i] { - return nil - } - if e[i] > p2[i] { - return errors.New("bn256: coordinate exceeds modulus") - } - } - return errors.New("bn256: coordinate equals modulus") -} - -// Note: This function is only used to distinguish between points with the same x-coordinates -// when doing point compression. -// An ordered field must be infinite and we are working over a finite field here -func gfpCmp(a, b *gfP) int { - for i := FpUint64Size - 1; i >= 0; i-- { // Remember that the gfP elements are written as little-endian 64-bit words - if a[i] > b[i] { // As soon as we figure out that the MSByte of A > MSByte of B, we return - return 1 - } else if a[i] == b[i] { // If the current bytes are equal we continue as we cannot conclude on A and B relation - continue - } else { // a[i] < b[i] so we can directly conclude and we return - return -1 - } - } - - return 0 -} - -// In Montgomery representation, an element x is represented by xR mod p, where -// R is a power of 2 corresponding to the number of machine-words that can contain p. -// (where p is the characteristic of the prime field we work over) -// See: https://web.wpi.edu/Pubs/ETD/Available/etd-0430102-120529/unrestricted/thesis.pdf -func montEncode(c, a *gfP) { gfpMul(c, a, r2) } -func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) } diff --git a/crypto/bn256/gfp12.go b/crypto/bn256/gfp12.go deleted file mode 100644 index 287b8be..0000000 --- a/crypto/bn256/gfp12.go +++ /dev/null @@ -1,160 +0,0 @@ -package bn256 - -// For details of the algorithms used, see "Multiplication and Squaring on -// Pairing-Friendly Fields, Devegili et al. -// http://eprint.iacr.org/2006/471.pdf. - -import ( - "math/big" -) - -// gfP12 implements the field of size p¹² as a quadratic extension of gfP6 -// where ω²=τ. -type gfP12 struct { - x, y gfP6 // value is xω + y -} - -func (e *gfP12) String() string { - return "(" + e.x.String() + "," + e.y.String() + ")" -} - -func (e *gfP12) Set(a *gfP12) *gfP12 { - e.x.Set(&a.x) - e.y.Set(&a.y) - return e -} - -func (e *gfP12) SetZero() *gfP12 { - e.x.SetZero() - e.y.SetZero() - return e -} - -func (e *gfP12) SetOne() *gfP12 { - e.x.SetZero() - e.y.SetOne() - return e -} - -func (e *gfP12) IsZero() bool { - return e.x.IsZero() && e.y.IsZero() -} - -func (e *gfP12) IsOne() bool { - return e.x.IsZero() && e.y.IsOne() -} - -func (e *gfP12) Conjugate(a *gfP12) *gfP12 { - e.x.Neg(&a.x) - e.y.Set(&a.y) - return e -} - -func (e *gfP12) Neg(a *gfP12) *gfP12 { - e.x.Neg(&a.x) - e.y.Neg(&a.y) - return e -} - -// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p -func (e *gfP12) Frobenius(a *gfP12) *gfP12 { - e.x.Frobenius(&a.x) - e.y.Frobenius(&a.y) - e.x.MulScalar(&e.x, xiToPMinus1Over6) - return e -} - -// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p² -func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 { - e.x.FrobeniusP2(&a.x) - e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6) - e.y.FrobeniusP2(&a.y) - return e -} - -func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 { - e.x.FrobeniusP4(&a.x) - e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3) - e.y.FrobeniusP4(&a.y) - return e -} - -func (e *gfP12) Add(a, b *gfP12) *gfP12 { - e.x.Add(&a.x, &b.x) - e.y.Add(&a.y, &b.y) - return e -} - -func (e *gfP12) Sub(a, b *gfP12) *gfP12 { - e.x.Sub(&a.x, &b.x) - e.y.Sub(&a.y, &b.y) - return e -} - -func (e *gfP12) Mul(a, b *gfP12) *gfP12 { - tx := (&gfP6{}).Mul(&a.x, &b.y) - t := (&gfP6{}).Mul(&b.x, &a.y) - tx.Add(tx, t) - - ty := (&gfP6{}).Mul(&a.y, &b.y) - t.Mul(&a.x, &b.x).MulTau(t) - - e.x.Set(tx) - e.y.Add(ty, t) - return e -} - -func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { - e.x.Mul(&e.x, b) - e.y.Mul(&e.y, b) - return e -} - -func (e *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { - sum := (&gfP12{}).SetOne() - t := &gfP12{} - - for i := power.BitLen() - 1; i >= 0; i-- { - t.Square(sum) - if power.Bit(i) != 0 { - sum.Mul(t, a) - } else { - sum.Set(t) - } - } - - e.Set(sum) - return e -} - -func (e *gfP12) Square(a *gfP12) *gfP12 { - // Complex squaring algorithm - v0 := (&gfP6{}).Mul(&a.x, &a.y) - - t := (&gfP6{}).MulTau(&a.x) - t.Add(&a.y, t) - ty := (&gfP6{}).Add(&a.x, &a.y) - ty.Mul(ty, t).Sub(ty, v0) - t.MulTau(v0) - ty.Sub(ty, t) - - e.x.Add(v0, v0) - e.y.Set(ty) - return e -} - -func (e *gfP12) Invert(a *gfP12) *gfP12 { - // See "Implementing cryptographic pairings", M. Scott, section 3.2. - // ftp://136.206.11.249/pub/crypto/pairings.pdf - t1, t2 := &gfP6{}, &gfP6{} - - t1.Square(&a.x) - t2.Square(&a.y) - t1.MulTau(t1).Sub(t2, t1) - t2.Invert(t1) - - e.x.Neg(&a.x) - e.y.Set(&a.y) - e.MulScalar(e, t2) - return e -} diff --git a/crypto/bn256/gfp2.go b/crypto/bn256/gfp2.go deleted file mode 100644 index 766b177..0000000 --- a/crypto/bn256/gfp2.go +++ /dev/null @@ -1,327 +0,0 @@ -package bn256 - -import ( - "errors" - "math" - "math/big" -) - -// For details of the algorithms used, see "Multiplication and Squaring on -// Pairing-Friendly Fields, Devegili et al. -// http://eprint.iacr.org/2006/471.pdf. - -// gfP2 implements a field of size p² as a quadratic extension of the base field -// where i²=-1. -type gfP2 struct { - x, y gfP // value is xi+y. -} - -func gfP2Decode(in *gfP2) *gfP2 { - out := &gfP2{} - montDecode(&out.x, &in.x) - montDecode(&out.y, &in.y) - return out -} - -func (e *gfP2) String() string { - return "(" + e.x.String() + ", " + e.y.String() + ")" -} - -func (e *gfP2) Set(a *gfP2) *gfP2 { - e.x.Set(&a.x) - e.y.Set(&a.y) - return e -} - -func (e *gfP2) SetZero() *gfP2 { - e.x = gfP{0} - e.y = gfP{0} - return e -} - -func (e *gfP2) SetOne() *gfP2 { - e.x = gfP{0} - e.y = *newGFp(1) - return e -} - -func (e *gfP2) IsZero() bool { - zero := gfP{0} - return e.x == zero && e.y == zero -} - -func (e *gfP2) IsOne() bool { - zero, one := gfP{0}, *newGFp(1) - return e.x == zero && e.y == one -} - -func (e *gfP2) Conjugate(a *gfP2) *gfP2 { - e.y.Set(&a.y) - gfpNeg(&e.x, &a.x) - return e -} - -func (e *gfP2) Neg(a *gfP2) *gfP2 { - gfpNeg(&e.x, &a.x) - gfpNeg(&e.y, &a.y) - return e -} - -func (e *gfP2) Add(a, b *gfP2) *gfP2 { - gfpAdd(&e.x, &a.x, &b.x) - gfpAdd(&e.y, &a.y, &b.y) - return e -} - -func (e *gfP2) Sub(a, b *gfP2) *gfP2 { - gfpSub(&e.x, &a.x, &b.x) - gfpSub(&e.y, &a.y, &b.y) - return e -} - -// See "Multiplication and Squaring in Pairing-Friendly Fields", -// http://eprint.iacr.org/2006/471.pdf Section 3 "Schoolbook method" -func (e *gfP2) Mul(a, b *gfP2) *gfP2 { - tx, t := &gfP{}, &gfP{} - gfpMul(tx, &a.x, &b.y) // tx = a.x * b.y - gfpMul(t, &b.x, &a.y) // t = b.x * a.y - gfpAdd(tx, tx, t) // tx = a.x * b.y + b.x * a.y - - ty := &gfP{} - gfpMul(ty, &a.y, &b.y) // ty = a.y * b.y - gfpMul(t, &a.x, &b.x) // t = a.x * b.x - // We do a subtraction in the field since β = -1 in our case - // In fact, Fp2 is built using the irreducible polynomial X^2 - β, where β = -1 = p-1 - gfpSub(ty, ty, t) // ty = a.y * b.y - a.x * b.x - - e.x.Set(tx) // e.x = a.x * b.y + b.x * a.y - e.y.Set(ty) // e.y = a.y * b.y - a.x * b.x - return e -} - -func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 { - gfpMul(&e.x, &a.x, b) - gfpMul(&e.y, &a.y, b) - return e -} - -// MulXi sets e=ξa where ξ=i+9 and then returns e. -func (e *gfP2) MulXi(a *gfP2) *gfP2 { - // (xi+y)(i+9) = (9x+y)i+(9y-x) - tx := &gfP{} - gfpAdd(tx, &a.x, &a.x) - gfpAdd(tx, tx, tx) - gfpAdd(tx, tx, tx) - gfpAdd(tx, tx, &a.x) - - gfpAdd(tx, tx, &a.y) - - ty := &gfP{} - gfpAdd(ty, &a.y, &a.y) - gfpAdd(ty, ty, ty) - gfpAdd(ty, ty, ty) - gfpAdd(ty, ty, &a.y) - - gfpSub(ty, ty, &a.x) - - e.x.Set(tx) - e.y.Set(ty) - return e -} - -func (e *gfP2) Square(a *gfP2) *gfP2 { - // Complex squaring algorithm: - // (xi+y)² = (x+y)(y-x) + 2*i*x*y - // - "Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf"; Section 3 (Complex squaring) - // - URL: https://eprint.iacr.org/2006/471.pdf - // Here, since the non residue used is β = -1 in Fp, then we have: - // c0 = (a0 + a1)(a0 + βa1) - v0 - βv0 => c0 = (a0 + a1)(a0 - a1) - // c1 = 2v0, where v0 is a0 * a1 (= x * y, with our notations) - tx, ty := &gfP{}, &gfP{} - gfpSub(tx, &a.y, &a.x) // a.y - a.x - gfpAdd(ty, &a.x, &a.y) // a.x + a.y - gfpMul(ty, tx, ty) - - gfpMul(tx, &a.x, &a.y) - gfpAdd(tx, tx, tx) - - e.x.Set(tx) - e.y.Set(ty) - return e -} - -func (e *gfP2) Invert(a *gfP2) *gfP2 { - // See "Implementing cryptographic pairings", M. Scott, section 3.2. - // ftp://136.206.11.249/pub/crypto/pairings.pdf - t1, t2 := &gfP{}, &gfP{} - gfpMul(t1, &a.x, &a.x) - gfpMul(t2, &a.y, &a.y) - gfpAdd(t1, t1, t2) - - inv := &gfP{} - inv.Invert(t1) - - gfpNeg(t1, &a.x) - - gfpMul(&e.x, t1, inv) - gfpMul(&e.y, &a.y, inv) - return e -} - -// Exp is a function to exponentiate field elements -// This function navigates the big.Int binary representation -// from left to right (assumed to be in big endian) -// When going from left to right, each bit is checked, and when the first `1` bit is found -// the `foundOne` flag is set, and the "exponentiation begins" -// -// Eg: Let's assume that we want to exponentiate 3^5 -// then the exponent is 5 = 0000 0101 -// We navigate 0000 0101 from left to right until we reach 0000 0101 -// ^ -// | -// When this bit is reached, the flag `foundOne` is set, and and we do: -// res = res * 3 = 3 -// Then, we move on to the left to read the next bit, and since `foundOne` is set (ie: -// the exponentiation has started), then we square the result, and do: -// res = res * res = 3*3 = 3^2 -// The bit is `0`, so we continue -// Next bit is `1`, so we do: res = res * res = 3^2 * 3^2 = 3^4 -// and because the bit is `1`, then, we do res = res * 3 = 3^4 * 3 = 3^5 -// We reached the end of the bit string, so we can stop. -// -// The binary representation of the exponent is assumed to be binary big endian -// -// Careful, since `res` is initialized with SetOne() and since this function -// initializes the calling gfP2 to the one element of the Gfp2 which is montEncoded -// then, we need to make sure that the `e` element of gfP2 used to call the Exp function -// is also montEncoded (ie; both x and y are montEncoded) -/* -TODO: Refactor this function like this: -func (e *gfP2) Exp(a *gfP2, exponent *big.Int) *gfP2 { - sum := (&gfP2{}).SetOne() - t := &gfP2{} - - for i := exponent.BitLen() - 1; i >= 0; i-- { - t.Square(sum) - if exponent.Bit(i) != 0 { - sum.Mul(t, a) - } else { - sum.Set(t) - } - } - - e.Set(sum) - return e -} -*/ -func (e *gfP2) Exp(exponent *big.Int) *gfP2 { - res := &gfP2{} - res = res.SetOne() - - base := &gfP2{} - base = base.Set(e) - - foundOne := false - exponentBytes := exponent.Bytes() // big endian bytes slice - - for i := 0; i < len(exponentBytes); i++ { // for each byte (remember the slice is big endian) - for j := 0; j <= 7; j++ { // A byte contains the powers of 2 to 2^7 to 2^0 from left to right - if foundOne { - res = res.Mul(res, res) - } - - if uint(exponentBytes[i])&uint(math.Pow(2, float64(7-j))) != uint(0) { // a byte contains the powers of 2 from 2^7 to 2^0 hence why we do 2^(7-j) (big-endian assumed) - foundOne = true - res = res.Mul(res, base) - } - } - } - - e.Set(res) - return e -} - -// Sqrt returns the square root of e in GFp2 -// See: -// - "A High-Speed Square Root Algorithm for Extension Fields - Especially for Fast Extension Fields" -// - URL: https://core.ac.uk/download/pdf/12530172.pdf -// -// - "Square Roots Modulo p" -// - URL: http://www.cmat.edu.uy/~tornaria/pub/Tornaria-2002.pdf -// -// - "Faster square roots in annoying finite fields" -// - URL: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.21.9172 -func (e *gfP2) Sqrt() (*gfP2, error) { - // In GF(p^m), Euler's Criterion is defined like EC(x) = x^((p^m -1) / 2), if EC(x) == 1, x is a QR; if EC(x) == -1, x is a QNR - // `euler` here, is the exponent used in Euler's criterion, thus, euler = (p^m -1) / 2 for GF(p^m) - // here, we work over GF(p^2), so euler = (p^2 -1) / 2, where p = 21888242871839275222246405745257275088696311157297823662689037894645226208583 - ////euler := bigFromBase10("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944") - - // modulus^2 = 2^s * t + 1 => p^2 = 2^s * t + 1, where t is odd - // In our case, p^2 = 2^s * t + 1, where s = 4, t = 29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243 - ////t := bigFromBase10("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243") - ////s := bigFromBase10("4") - s := 4 - - // tMinus1Over2 = (t-1) / 2 - tMinus1Over2 := bigFromBase10("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621") - - // A non quadratic residue in Fp - ////nonResidueFp := bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582") - - // A non quadratic residue in Fp2. Here nonResidueFp2 = i + 2 (Euler Criterion applied to this element of Fp2 shows that this element is a QNR) - ////nonResidueFp2 := &gfP2{*newGFp(1), *newGFp(2)} - - // nonResidueFp2 ^ t - nonResidueFp2ToTXCoord := bigFromBase10("314498342015008975724433667930697407966947188435857772134235984660852259084") - nonResidueFp2ToTYCoord := bigFromBase10("5033503716262624267312492558379982687175200734934877598599011485707452665730") - nonResidueFp2ToT := &gfP2{*newMontEncodedGFpFromBigInt(nonResidueFp2ToTXCoord), *newMontEncodedGFpFromBigInt(nonResidueFp2ToTYCoord)} - - // Start algorithm - // Initialize the algorithm variables - v := s - z := nonResidueFp2ToT - w := new(gfP2).Set(e) - w = w.Exp(tMinus1Over2) - x := new(gfP2).Mul(e, w) - b := new(gfP2).Mul(x, w) // contains e^t - - // Check if the element is a QR - // Since p^2 = 2^s * t + 1 => t = (p^2 - 1)/2 - // Thus, since we have b = e^t, and since we want to test if e is a QR - // we need to square b (s-1) times. That way we'd have - // (e^t)^{2^(s-1)} which equals e^{(p^2 - 1)/2} => Euler criterion - bCheck := new(gfP2).Set(b) - for i := 0; i < s-1; i++ { // s-1 == 3 here (see comment above) - bCheck = bCheck.Square(bCheck) - } - - if !bCheck.IsOne() { - return nil, errors.New("Cannot extract a root. The element is not a QR in Fp2") - } - - // Extract the root of the quadratic residue using the Tonelli-Shanks algorithm - for !b.IsOne() { - m := 0 - b2m := new(gfP2).Set(b) - for !b2m.IsOne() { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.Square(b2m) - m++ - } - - j := v - m - 1 - w = z - for j > 0 { - w = w.Square(w) - j-- - } // w = z^2^(v-m-1) - - z = new(gfP2).Square(w) - b = b.Mul(b, z) - x = x.Mul(x, w) - v = m - } - - return x, nil -} diff --git a/crypto/bn256/gfp2_test.go b/crypto/bn256/gfp2_test.go deleted file mode 100644 index cfbdb29..0000000 --- a/crypto/bn256/gfp2_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package bn256 - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// Tests that the exponentiation in gfp2 works correctly -// SageMath test vector: -/* -p = 21888242871839275222246405745257275088696311157297823662689037894645226208583 -Fp = GF(p) -Fpx. = PolynomialRing(Fp, 'j') -// The modulus is in the form `j^2 - non-residue-in-Fp` -// Fp2. = GF(p^2, modulus=j^2 - 3) // 3 is a quadratic non-residue in Fp -// See: https://github.com/scipr-lab/libff/blob/master/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp#L95 -// The quadratic non-residue used in -1, so the modulus is -Fp2. = GF(p^2, modulus=j^2 + 1) - -// Quad. Non. Resid. test (Euler's criterion) -eulerExp = (Fp(p-1)/Fp(2)) -Fp(-1)^eulerExp + Fp(1) == p // Should return true, then we see that -1 (ie: p-1) is a nqr (non quadratic residue mod p) - -// Element taken randomly in the field Fp2 -// we denote an element of Fp2 as: e = x*i + y -baseElement = 8192512702373747571754527085437364828369119615795326562285198594140975111129*i + 14719814144181528030533020377409648968040866053797156997322427920899698335369 - -// baseElementXHex = hex(8192512702373747571754527085437364828369119615795326562285198594140975111129) -baseElementXHex = 121ccc410d6339f7 bbc9a8f5b577c5c5 96c9dfdd6233cbac 34a8ddeafedf9bd9 -baseElementXHexLittleEndian = 34a8ddeafedf9bd9 96c9dfdd6233cbac bbc9a8f5b577c5c5 121ccc410d6339f7 - -// baseElementYHex = hex(14719814144181528030533020377409648968040866053797156997322427920899698335369) -baseElementYHex = 208b1e9b9b11a98c 30a84b2641e87244 9a54780d0e482cfb 146adf9eb7641e89 -baseElementYHexLittleEndian = 146adf9eb7641e89 9a54780d0e482cfb 30a84b2641e87244 208b1e9b9b11a98c - -// We run in Sage, resExponentiation = baseElement ^ 5, and we get -baseElementTo5 = baseElement ^ 5 -baseElementTo5 = 1919494216989370714282264091499504460829540920627494019318177103740489354093*i + 3944397571509712892671395330294281468555185483198747137614153093242854529958 -baseElementTo5XHex = 043e652d8f044857 c4cbfe9636928309 44288a2a00432390 7fa7e33a3e5acb6d -baseElementTo5XHexLittleEndian = 7fa7e33a3e5acb6d 44288a2a00432390 c4cbfe9636928309 043e652d8f044857 - -baseElementTo5YHex = 08b8732d547b1cda b5c82ff0bfaa42c1 54e7b24b65223fc2 88b3e8a6de535ba6 -baseElementTo5XHexLittleEndian = 88b3e8a6de535ba6 54e7b24b65223fc2 b5c82ff0bfaa42c1 08b8732d547b1cda -*/ -func TestExp(t *testing.T) { - // Case 1: Exponent = 5 (= 0x05) - baseElementX := &gfP{0x34a8ddeafedf9bd9, 0x96c9dfdd6233cbac, 0xbbc9a8f5b577c5c5, 0x121ccc410d6339f7} - baseElementY := &gfP{0x146adf9eb7641e89, 0x9a54780d0e482cfb, 0x30a84b2641e87244, 0x208b1e9b9b11a98c} - // montEncode each Fp element - // Important to do since the field arithmetic uses montgomery encoding in the library - montEncode(baseElementX, baseElementX) - montEncode(baseElementY, baseElementY) - baseElement := &gfP2{*baseElementX, *baseElementY} - - // We keep the expected result non encoded - // Will need to decode the obtained result to be able to assert it with this - baseElementTo5X := &gfP{0x7fa7e33a3e5acb6d, 0x44288a2a00432390, 0xc4cbfe9636928309, 0x043e652d8f044857} - baseElementTo5Y := &gfP{0x88b3e8a6de535ba6, 0x54e7b24b65223fc2, 0xb5c82ff0bfaa42c1, 0x08b8732d547b1cda} - baseElementTo5 := &gfP2{*baseElementTo5X, *baseElementTo5Y} - - // Manual multiplication, to make sure the results are all coherent with each other - manual := &gfP2{} - manual = manual.Set(baseElement) - manual = manual.Mul(manual, manual) // manual ^ 2 - manual = manual.Mul(manual, manual) // manual ^ 4 - manual = manual.Mul(manual, baseElement) // manual ^ 5 - manualDecoded := gfP2Decode(manual) - - // Expected result (obtained with sagemath, after some type conversions) - w := &gfP2{} - w = w.Set(baseElementTo5) - - // Result returned by the Exp function - exponent5 := bigFromBase10("5") - h := &gfP2{} - h = h.Set(baseElement) - h = h.Exp(exponent5) - - // We decode the result of the exponentiation to be able to compare with the - // non-encoded/sagemath generated expected result - hDecoded := gfP2Decode(h) - - assert.Equal(t, *w, *hDecoded, "The result of the exponentiation is not coherent with the Sagemath test vector") - assert.Equal(t, *manualDecoded, *hDecoded, "The result of the exponentiation is not coherent with the manual repeated multiplication") - - // Case 2: Exponent = bigExponent = 39028236692093846773374607431768211455 + 2^128 - 2^64 = 379310603613032310218302470789826871295 = 0x11d5c90a20486bd1c40686b493777ffff - // This exponent can be encoded on 3 words/uint64 => 0x1 0x1d5c90a20486bd1c 0x40686b493777ffff if 64bit machine or - // on 5 words/uint32 => 0x1 0x1d5c90a2 0x0486bd1c 0x40686b49 0x3777ffff if 32bit machine - baseElementX = &gfP{0x34a8ddeafedf9bd9, 0x96c9dfdd6233cbac, 0xbbc9a8f5b577c5c5, 0x121ccc410d6339f7} - baseElementY = &gfP{0x146adf9eb7641e89, 0x9a54780d0e482cfb, 0x30a84b2641e87244, 0x208b1e9b9b11a98c} - // montEncode each Fp element - // Important to do since the field arithmetic uses montgomery encoding in the library - montEncode(baseElementX, baseElementX) - montEncode(baseElementY, baseElementY) - baseElement = &gfP2{*baseElementX, *baseElementY} - - // We keep the expected result non encoded - // Will need to decode the obtained result to be able to assert it with this - // Sagemath: - // baseElementToBigExp = baseElement ^ bigExponent - // baseElementToBigExp => 7379142427977467878031119988604583496475317621776403696479934226513132928021*i + 17154720713365092794088637301427106756251681045968150072197181728711103784706 - // baseElementToBigExpXHex = 10507254ce787236 62cf3f84eb21adee 30ec827a799a519a 1464fc2ec9263c15 - // baseElementToBigExpYHex = 25ed3a53d558db9a 07da01cc9d10c5d5 ff7b1e4f41b874d7 debbc13409c8a702 - baseElementToBigExpX := &gfP{0x1464fc2ec9263c15, 0x30ec827a799a519a, 0x62cf3f84eb21adee, 0x10507254ce787236} - baseElementToBigExpY := &gfP{0xdebbc13409c8a702, 0xff7b1e4f41b874d7, 0x07da01cc9d10c5d5, 0x25ed3a53d558db9a} - baseElementToBigExp := &gfP2{*baseElementToBigExpX, *baseElementToBigExpY} - - // Expected result (obtained with sagemath, after some type conversions) - w = &gfP2{} - w = w.Set(baseElementToBigExp) - - // Result returned by the Exp function - bigExp := bigFromBase10("379310603613032310218302470789826871295") - h = &gfP2{} - h = h.Set(baseElement) - h = h.Exp(bigExp) - - // We decode the result of the exponentiation to be able to compare with the - // non-encoded/sagemath generated expected result - hDecoded = gfP2Decode(h) - - assert.Equal(t, *w, *hDecoded, "The result of the exponentiation is not coherent with the Sagemath test vector") -} - -func TestSqrt(t *testing.T) { - // Case 1: Valid QR - // qr = 8192512702373747571754527085437364828369119615795326562285198594140975111129*i + 14719814144181528030533020377409648968040866053797156997322427920899698335369 - // This is a QR in Fp2 - qrXBig := bigFromBase10("8192512702373747571754527085437364828369119615795326562285198594140975111129") - qrYBig := bigFromBase10("14719814144181528030533020377409648968040866053797156997322427920899698335369") - qr := &gfP2{*newMontEncodedGFpFromBigInt(qrXBig), *newMontEncodedGFpFromBigInt(qrYBig)} - res, err := qr.Sqrt() - assert.NoError(t, err, "An error shouldn't be returned as we try to get the sqrt of a QR") - // We decode the result of the squaring to compare the result with the Sagemath test vector - // To get the sqrt of `r` in Sage, we run: `r.sqrt()`, and we get: - // 838738240039331261565244756819667559640832302782323121523807597830118111128*i + 701115843855913009657260259360827182296091347204618857804078039211229345012 - resDecoded := gfP2Decode(res) - expectedXBig := bigFromBase10("838738240039331261565244756819667559640832302782323121523807597830118111128") - expectedYBig := bigFromBase10("701115843855913009657260259360827182296091347204618857804078039211229345012") - expected := &gfP2{*newGFpFromBigInt(expectedXBig), *newGFpFromBigInt(expectedYBig)} - - assert.Equal(t, *expected, *resDecoded, "The result of the sqrt is not coherent with the Sagemath test vector") - - // Case 2: Valid QR - // qr = -1 = 0 * i + 21888242871839275222246405745257275088696311157297823662689037894645226208582 - // The sqrt of qr is: sqrt = 21888242871839275222246405745257275088696311157297823662689037894645226208582 * i + 0 - qr = &gfP2{*newGFp(0), *newMontEncodedGFpFromBigInt(bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582"))} - res, err = qr.Sqrt() - assert.NoError(t, err, "An error shouldn't be returned as we try to get the sqrt of a QR") - - resDecoded = gfP2Decode(res) - expected = &gfP2{*newGFpFromBigInt(bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582")), *newGFp(0)} - assert.Equal(t, *expected, *resDecoded, "The result of the sqrt is not coherent with the Sagemath test vector") - - // Case 3: Get the sqrt of a QNR - // qnr = 10142231111593789910248975994434553601587001629804098271704323146176084338608*i + 13558357083504759335548106329923635779485621365040524539176938811542516618464 - qnrXBig := bigFromBase10("10142231111593789910248975994434553601587001629804098271704323146176084338608") - qnrYBig := bigFromBase10("13558357083504759335548106329923635779485621365040524539176938811542516618464") - qnr := &gfP2{*newMontEncodedGFpFromBigInt(qnrXBig), *newMontEncodedGFpFromBigInt(qnrYBig)} - res, err = qnr.Sqrt() - assert.Error(t, err, "An error should have been returned as we try to get the sqrt of a QNR") - assert.Nil(t, res, "The result of sqrt should be nil as we try to get the sqrt of a QNR") -} diff --git a/crypto/bn256/gfp6.go b/crypto/bn256/gfp6.go deleted file mode 100644 index 83d61b7..0000000 --- a/crypto/bn256/gfp6.go +++ /dev/null @@ -1,213 +0,0 @@ -package bn256 - -// For details of the algorithms used, see "Multiplication and Squaring on -// Pairing-Friendly Fields, Devegili et al. -// http://eprint.iacr.org/2006/471.pdf. - -// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ -// and ξ=i+3. -type gfP6 struct { - x, y, z gfP2 // value is xτ² + yτ + z -} - -func (e *gfP6) String() string { - return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")" -} - -func (e *gfP6) Set(a *gfP6) *gfP6 { - e.x.Set(&a.x) - e.y.Set(&a.y) - e.z.Set(&a.z) - return e -} - -func (e *gfP6) SetZero() *gfP6 { - e.x.SetZero() - e.y.SetZero() - e.z.SetZero() - return e -} - -func (e *gfP6) SetOne() *gfP6 { - e.x.SetZero() - e.y.SetZero() - e.z.SetOne() - return e -} - -func (e *gfP6) IsZero() bool { - return e.x.IsZero() && e.y.IsZero() && e.z.IsZero() -} - -func (e *gfP6) IsOne() bool { - return e.x.IsZero() && e.y.IsZero() && e.z.IsOne() -} - -func (e *gfP6) Neg(a *gfP6) *gfP6 { - e.x.Neg(&a.x) - e.y.Neg(&a.y) - e.z.Neg(&a.z) - return e -} - -func (e *gfP6) Frobenius(a *gfP6) *gfP6 { - e.x.Conjugate(&a.x) - e.y.Conjugate(&a.y) - e.z.Conjugate(&a.z) - - e.x.Mul(&e.x, xiTo2PMinus2Over3) - e.y.Mul(&e.y, xiToPMinus1Over3) - return e -} - -// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z -func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 { - // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3) - e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3) - // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3) - e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3) - e.z.Set(&a.z) - return e -} - -func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 { - e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3) - e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3) - e.z.Set(&a.z) - return e -} - -func (e *gfP6) Add(a, b *gfP6) *gfP6 { - e.x.Add(&a.x, &b.x) - e.y.Add(&a.y, &b.y) - e.z.Add(&a.z, &b.z) - return e -} - -func (e *gfP6) Sub(a, b *gfP6) *gfP6 { - e.x.Sub(&a.x, &b.x) - e.y.Sub(&a.y, &b.y) - e.z.Sub(&a.z, &b.z) - return e -} - -func (e *gfP6) Mul(a, b *gfP6) *gfP6 { - // "Multiplication and Squaring on Pairing-Friendly Fields" - // Section 4, Karatsuba method. - // http://eprint.iacr.org/2006/471.pdf - v0 := (&gfP2{}).Mul(&a.z, &b.z) - v1 := (&gfP2{}).Mul(&a.y, &b.y) - v2 := (&gfP2{}).Mul(&a.x, &b.x) - - t0 := (&gfP2{}).Add(&a.x, &a.y) - t1 := (&gfP2{}).Add(&b.x, &b.y) - tz := (&gfP2{}).Mul(t0, t1) - tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0) - - t0.Add(&a.y, &a.z) - t1.Add(&b.y, &b.z) - ty := (&gfP2{}).Mul(t0, t1) - t0.MulXi(v2) - ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0) - - t0.Add(&a.x, &a.z) - t1.Add(&b.x, &b.z) - tx := (&gfP2{}).Mul(t0, t1) - tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2) - - e.x.Set(tx) - e.y.Set(ty) - e.z.Set(tz) - return e -} - -func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 { - e.x.Mul(&a.x, b) - e.y.Mul(&a.y, b) - e.z.Mul(&a.z, b) - return e -} - -func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 { - e.x.MulScalar(&a.x, b) - e.y.MulScalar(&a.y, b) - e.z.MulScalar(&a.z, b) - return e -} - -// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ -func (e *gfP6) MulTau(a *gfP6) *gfP6 { - tz := (&gfP2{}).MulXi(&a.x) - ty := (&gfP2{}).Set(&a.y) - - e.y.Set(&a.z) - e.x.Set(ty) - e.z.Set(tz) - return e -} - -func (e *gfP6) Square(a *gfP6) *gfP6 { - v0 := (&gfP2{}).Square(&a.z) - v1 := (&gfP2{}).Square(&a.y) - v2 := (&gfP2{}).Square(&a.x) - - c0 := (&gfP2{}).Add(&a.x, &a.y) - c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0) - - c1 := (&gfP2{}).Add(&a.y, &a.z) - c1.Square(c1).Sub(c1, v0).Sub(c1, v1) - xiV2 := (&gfP2{}).MulXi(v2) - c1.Add(c1, xiV2) - - c2 := (&gfP2{}).Add(&a.x, &a.z) - c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2) - - e.x.Set(c2) - e.y.Set(c1) - e.z.Set(c0) - return e -} - -func (e *gfP6) Invert(a *gfP6) *gfP6 { - // See "Implementing cryptographic pairings", M. Scott, section 3.2. - // ftp://136.206.11.249/pub/crypto/pairings.pdf - - // Here we can give a short explanation of how it works: let j be a cubic root of - // unity in GF(p²) so that 1+j+j²=0. - // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z) - // = (xτ² + yτ + z)(Cτ²+Bτ+A) - // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm). - // - // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z) - // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) - // - // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) - t1 := (&gfP2{}).Mul(&a.x, &a.y) - t1.MulXi(t1) - - A := (&gfP2{}).Square(&a.z) - A.Sub(A, t1) - - B := (&gfP2{}).Square(&a.x) - B.MulXi(B) - t1.Mul(&a.y, &a.z) - B.Sub(B, t1) - - C := (&gfP2{}).Square(&a.y) - t1.Mul(&a.x, &a.z) - C.Sub(C, t1) - - F := (&gfP2{}).Mul(C, &a.y) - F.MulXi(F) - t1.Mul(A, &a.z) - F.Add(F, t1) - t1.Mul(B, &a.x).MulXi(t1) - F.Add(F, t1) - - F.Invert(F) - - e.x.Mul(C, F) - e.y.Mul(B, F) - e.z.Mul(A, F) - return e -} diff --git a/crypto/bn256/gfp_amd64.s b/crypto/bn256/gfp_amd64.s deleted file mode 100644 index bdb4ffb..0000000 --- a/crypto/bn256/gfp_amd64.s +++ /dev/null @@ -1,129 +0,0 @@ -// +build amd64,!generic - -#define storeBlock(a0,a1,a2,a3, r) \ - MOVQ a0, 0+r \ - MOVQ a1, 8+r \ - MOVQ a2, 16+r \ - MOVQ a3, 24+r - -#define loadBlock(r, a0,a1,a2,a3) \ - MOVQ 0+r, a0 \ - MOVQ 8+r, a1 \ - MOVQ 16+r, a2 \ - MOVQ 24+r, a3 - -#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \ - \ // b = a-p - MOVQ a0, b0 \ - MOVQ a1, b1 \ - MOVQ a2, b2 \ - MOVQ a3, b3 \ - MOVQ a4, b4 \ - \ - SUBQ ·p2+0(SB), b0 \ - SBBQ ·p2+8(SB), b1 \ - SBBQ ·p2+16(SB), b2 \ - SBBQ ·p2+24(SB), b3 \ - SBBQ $0, b4 \ - \ - \ // if b is negative then return a - \ // else return b - CMOVQCC b0, a0 \ - CMOVQCC b1, a1 \ - CMOVQCC b2, a2 \ - CMOVQCC b3, a3 - -#include "mul_amd64.h" -#include "mul_bmi2_amd64.h" - -TEXT ·gfpNeg(SB),0,$0-16 - MOVQ ·p2+0(SB), R8 - MOVQ ·p2+8(SB), R9 - MOVQ ·p2+16(SB), R10 - MOVQ ·p2+24(SB), R11 - - MOVQ a+8(FP), DI - SUBQ 0(DI), R8 - SBBQ 8(DI), R9 - SBBQ 16(DI), R10 - SBBQ 24(DI), R11 - - MOVQ $0, AX - gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,R15,BX) - - MOVQ c+0(FP), DI - storeBlock(R8,R9,R10,R11, 0(DI)) - RET - -TEXT ·gfpAdd(SB),0,$0-24 - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - - loadBlock(0(DI), R8,R9,R10,R11) - MOVQ $0, R12 - - ADDQ 0(SI), R8 - ADCQ 8(SI), R9 - ADCQ 16(SI), R10 - ADCQ 24(SI), R11 - ADCQ $0, R12 - - gfpCarry(R8,R9,R10,R11,R12, R13,R14,R15,AX,BX) - - MOVQ c+0(FP), DI - storeBlock(R8,R9,R10,R11, 0(DI)) - RET - -TEXT ·gfpSub(SB),0,$0-24 - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - - loadBlock(0(DI), R8,R9,R10,R11) - - MOVQ ·p2+0(SB), R12 - MOVQ ·p2+8(SB), R13 - MOVQ ·p2+16(SB), R14 - MOVQ ·p2+24(SB), R15 - MOVQ $0, AX - - SUBQ 0(SI), R8 - SBBQ 8(SI), R9 - SBBQ 16(SI), R10 - SBBQ 24(SI), R11 - - CMOVQCC AX, R12 - CMOVQCC AX, R13 - CMOVQCC AX, R14 - CMOVQCC AX, R15 - - ADDQ R12, R8 - ADCQ R13, R9 - ADCQ R14, R10 - ADCQ R15, R11 - - MOVQ c+0(FP), DI - storeBlock(R8,R9,R10,R11, 0(DI)) - RET - -TEXT ·gfpMul(SB),0,$160-24 - MOVQ a+8(FP), DI - MOVQ b+16(FP), SI - - // Jump to a slightly different implementation if MULX isn't supported. - CMPB ·hasBMI2(SB), $0 - JE nobmi2Mul - - mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI)) - storeBlock( R8, R9,R10,R11, 0(SP)) - storeBlock(R12,R13,R14,R15, 32(SP)) - gfpReduceBMI2() - JMP end - -nobmi2Mul: - mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP)) - gfpReduce(0(SP)) - -end: - MOVQ c+0(FP), DI - storeBlock(R12,R13,R14,R15, 0(DI)) - RET diff --git a/crypto/bn256/gfp_arm64.s b/crypto/bn256/gfp_arm64.s deleted file mode 100644 index c65e801..0000000 --- a/crypto/bn256/gfp_arm64.s +++ /dev/null @@ -1,113 +0,0 @@ -// +build arm64,!generic - -#define storeBlock(a0,a1,a2,a3, r) \ - MOVD a0, 0+r \ - MOVD a1, 8+r \ - MOVD a2, 16+r \ - MOVD a3, 24+r - -#define loadBlock(r, a0,a1,a2,a3) \ - MOVD 0+r, a0 \ - MOVD 8+r, a1 \ - MOVD 16+r, a2 \ - MOVD 24+r, a3 - -#define loadModulus(p0,p1,p2,p3) \ - MOVD ·p2+0(SB), p0 \ - MOVD ·p2+8(SB), p1 \ - MOVD ·p2+16(SB), p2 \ - MOVD ·p2+24(SB), p3 - -#include "mul_arm64.h" - -TEXT ·gfpNeg(SB),0,$0-16 - MOVD a+8(FP), R0 - loadBlock(0(R0), R1,R2,R3,R4) - loadModulus(R5,R6,R7,R8) - - SUBS R1, R5, R1 - SBCS R2, R6, R2 - SBCS R3, R7, R3 - SBCS R4, R8, R4 - - SUBS R5, R1, R5 - SBCS R6, R2, R6 - SBCS R7, R3, R7 - SBCS R8, R4, R8 - - CSEL CS, R5, R1, R1 - CSEL CS, R6, R2, R2 - CSEL CS, R7, R3, R3 - CSEL CS, R8, R4, R4 - - MOVD c+0(FP), R0 - storeBlock(R1,R2,R3,R4, 0(R0)) - RET - -TEXT ·gfpAdd(SB),0,$0-24 - MOVD a+8(FP), R0 - loadBlock(0(R0), R1,R2,R3,R4) - MOVD b+16(FP), R0 - loadBlock(0(R0), R5,R6,R7,R8) - loadModulus(R9,R10,R11,R12) - MOVD ZR, R0 - - ADDS R5, R1 - ADCS R6, R2 - ADCS R7, R3 - ADCS R8, R4 - ADCS ZR, R0 - - SUBS R9, R1, R5 - SBCS R10, R2, R6 - SBCS R11, R3, R7 - SBCS R12, R4, R8 - SBCS ZR, R0, R0 - - CSEL CS, R5, R1, R1 - CSEL CS, R6, R2, R2 - CSEL CS, R7, R3, R3 - CSEL CS, R8, R4, R4 - - MOVD c+0(FP), R0 - storeBlock(R1,R2,R3,R4, 0(R0)) - RET - -TEXT ·gfpSub(SB),0,$0-24 - MOVD a+8(FP), R0 - loadBlock(0(R0), R1,R2,R3,R4) - MOVD b+16(FP), R0 - loadBlock(0(R0), R5,R6,R7,R8) - loadModulus(R9,R10,R11,R12) - - SUBS R5, R1 - SBCS R6, R2 - SBCS R7, R3 - SBCS R8, R4 - - CSEL CS, ZR, R9, R9 - CSEL CS, ZR, R10, R10 - CSEL CS, ZR, R11, R11 - CSEL CS, ZR, R12, R12 - - ADDS R9, R1 - ADCS R10, R2 - ADCS R11, R3 - ADCS R12, R4 - - MOVD c+0(FP), R0 - storeBlock(R1,R2,R3,R4, 0(R0)) - RET - -TEXT ·gfpMul(SB),0,$0-24 - MOVD a+8(FP), R0 - loadBlock(0(R0), R1,R2,R3,R4) - MOVD b+16(FP), R0 - loadBlock(0(R0), R5,R6,R7,R8) - - mul(R9,R10,R11,R12,R13,R14,R15,R16) - gfpReduce() - - MOVD c+0(FP), R0 - storeBlock(R1,R2,R3,R4, 0(R0)) - RET diff --git a/crypto/bn256/gfp_decl.go b/crypto/bn256/gfp_decl.go deleted file mode 100644 index fdea5c1..0000000 --- a/crypto/bn256/gfp_decl.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build amd64,!generic arm64,!generic - -package bn256 - -// This file contains forward declarations for the architecture-specific -// assembly implementations of these functions, provided that they exist. - -import ( - "golang.org/x/sys/cpu" -) - -//nolint:varcheck -var hasBMI2 = cpu.X86.HasBMI2 - -// go:noescape -func gfpNeg(c, a *gfP) - -//go:noescape -func gfpAdd(c, a, b *gfP) - -//go:noescape -func gfpSub(c, a, b *gfP) - -//go:noescape -func gfpMul(c, a, b *gfP) diff --git a/crypto/bn256/gfp_generic.go b/crypto/bn256/gfp_generic.go deleted file mode 100644 index d902aa7..0000000 --- a/crypto/bn256/gfp_generic.go +++ /dev/null @@ -1,209 +0,0 @@ -// +build !amd64,!arm64 generic - -package bn256 - -func gfpCarry(a *gfP, head uint64) { - b := &gfP{} - - var carry uint64 - for i, pi := range p2 { - ai := a[i] - bi := ai - pi - carry - b[i] = bi - carry = (pi&^ai | (pi|^ai)&bi) >> 63 - } - carry = carry &^ head - - // If b is negative, then return a. - // Else return b. - carry = -carry - ncarry := ^carry - for i := 0; i < 4; i++ { - a[i] = (a[i] & carry) | (b[i] & ncarry) - } -} - -func gfpNeg(c, a *gfP) { - var carry uint64 - for i, pi := range p2 { // p2 being the prime that defines the base/prime field - ai := a[i] - ci := pi - ai - carry - c[i] = ci - carry = (ai&^pi | (ai|^pi)&ci) >> 63 - } - gfpCarry(c, 0) -} - -func gfpAdd(c, a, b *gfP) { - var carry uint64 - for i, ai := range a { - bi := b[i] - ci := ai + bi + carry - c[i] = ci - carry = (ai&bi | (ai|bi)&^ci) >> 63 - } - gfpCarry(c, carry) -} - -func gfpSub(c, a, b *gfP) { - t := &gfP{} - - var carry uint64 - for i, pi := range p2 { - bi := b[i] - ti := pi - bi - carry - t[i] = ti - carry = (bi&^pi | (bi|^pi)&ti) >> 63 - } - - carry = 0 - for i, ai := range a { - ti := t[i] - ci := ai + ti + carry - c[i] = ci - carry = (ai&ti | (ai|ti)&^ci) >> 63 - } - gfpCarry(c, carry) -} - -func mul(a, b [4]uint64) [8]uint64 { - const ( - mask16 uint64 = 0x0000ffff - mask32 uint64 = 0xffffffff - ) - - var buff [32]uint64 - for i, ai := range a { - a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 - - for j, bj := range b { - b0, b2 := bj&mask32, bj>>32 - - off := 4 * (i + j) - buff[off+0] += a0 * b0 - buff[off+1] += a1 * b0 - buff[off+2] += a2*b0 + a0*b2 - buff[off+3] += a3*b0 + a1*b2 - buff[off+4] += a2 * b2 - buff[off+5] += a3 * b2 - } - } - - for i := uint(1); i < 4; i++ { - shift := 16 * i - - var head, carry uint64 - for j := uint(0); j < 8; j++ { - block := 4 * j - - xi := buff[block] - yi := (buff[block+i] << shift) + head - zi := xi + yi + carry - buff[block] = zi - carry = (xi&yi | (xi|yi)&^zi) >> 63 - - head = buff[block+i] >> (64 - shift) - } - } - - return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]} -} - -func halfMul(a, b [4]uint64) [4]uint64 { - const ( - mask16 uint64 = 0x0000ffff - mask32 uint64 = 0xffffffff - ) - - var buff [18]uint64 - for i, ai := range a { - a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 - - for j, bj := range b { - if i+j > 3 { - break - } - b0, b2 := bj&mask32, bj>>32 - - off := 4 * (i + j) - buff[off+0] += a0 * b0 - buff[off+1] += a1 * b0 - buff[off+2] += a2*b0 + a0*b2 - buff[off+3] += a3*b0 + a1*b2 - buff[off+4] += a2 * b2 - buff[off+5] += a3 * b2 - } - } - - for i := uint(1); i < 4; i++ { - shift := 16 * i - - var head, carry uint64 - for j := uint(0); j < 4; j++ { - block := 4 * j - - xi := buff[block] - yi := (buff[block+i] << shift) + head - zi := xi + yi + carry - buff[block] = zi - carry = (xi&yi | (xi|yi)&^zi) >> 63 - - head = buff[block+i] >> (64 - shift) - } - } - - return [4]uint64{buff[0], buff[4], buff[8], buff[12]} -} - -func gfpMul(c, a, b *gfP) { - T := mul(*a, *b) - m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np) - t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2) - - var carry uint64 - for i, Ti := range T { - ti := t[i] - zi := Ti + ti + carry - T[i] = zi - carry = (Ti&ti | (Ti|ti)&^zi) >> 63 - } - - *c = gfP{T[4], T[5], T[6], T[7]} - gfpCarry(c, carry) -} - -// Util function to compare field elements. Should be defined in gfP files -// Compares 2 GFp elements -// Returns 1 if a > b; 0 if a == b; -1 if a < b -/* -func gfpCmp(a, b *gfP) int { - for i := FpUint64Size - 1; i >= 0; i-- { // Remember that the gfP elements are written as little-endian 64-bit words - if a[i] > b[i] { // As soon as we figure out that the MSByte of A > MSByte of B, we return - return 1 - } else if a[i] == b[i] { // If the current bytes are equal we continue as we cannot conclude on A and B relation - continue - } else { // a[i] < b[i] so we can directly conclude and we return - return -1 - } - } - - return 0 -} -*/ - -// TODO: Optimize these functions as for now all it's doing is to convert in big.Int -// and use big integer arithmetic -// Computes c = a^{exp} in Fp (so mod p) -/* -func gfpExp(a *gfP, exp, mod *big.Int) *gfP { - // Convert the field elements to big.Int - aBig := a.gFpToBigInt() - - // Run the big.Int Exp algorithm - resBig := new(big.Int).Exp(aBig, exp, mod) - - // Convert the big.Int result back to field element - res := newGFpFromBigInt(resBig) - return res -} -*/ diff --git a/crypto/bn256/gfp_test.go b/crypto/bn256/gfp_test.go deleted file mode 100644 index 6fe2872..0000000 --- a/crypto/bn256/gfp_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package bn256 - -import ( - "testing" -) - -// Tests that negation works the same way on both assembly-optimized and pure Go -// implementation. -func TestGFpNeg(t *testing.T) { - n := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} - w := &gfP{0xfedcba9876543211, 0x0123456789abcdef, 0x2152411021524110, 0x0114251201142512} - h := &gfP{} - - gfpNeg(h, n) - if *h != *w { - t.Errorf("negation mismatch: have %#x, want %#x", *h, *w) - } -} - -// Tests that addition works the same way on both assembly-optimized and pure Go -// implementation. -func TestGFpAdd(t *testing.T) { - a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} - b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} - w := &gfP{0xc3df73e9278302b8, 0x687e956e978e3572, 0x254954275c18417f, 0xad354b6afc67f9b4} - h := &gfP{} - - gfpAdd(h, a, b) - if *h != *w { - t.Errorf("addition mismatch: have %#x, want %#x", *h, *w) - } -} - -// Tests that subtraction works the same way on both assembly-optimized and pure Go -// implementation. -func TestGFpSub(t *testing.T) { - a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} - b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} - w := &gfP{0x02468acf13579bdf, 0xfdb97530eca86420, 0xdfc1e401dfc1e402, 0x203e1bfe203e1bfd} - h := &gfP{} - - gfpSub(h, a, b) - if *h != *w { - t.Errorf("subtraction mismatch: have %#x, want %#x", *h, *w) - } -} - -// Tests that multiplication works the same way on both assembly-optimized and pure Go -// implementation. -func TestGFpMul(t *testing.T) { - a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed} - b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef} - w := &gfP{0xcbcbd377f7ad22d3, 0x3b89ba5d849379bf, 0x87b61627bd38b6d2, 0xc44052a2a0e654b2} - h := &gfP{} - - gfpMul(h, a, b) - if *h != *w { - t.Errorf("multiplication mismatch: have %#x, want %#x", *h, *w) - } -} - -// Tests the conversion from big.Int to GFp element -func TestNewGFpFromBigInt(t *testing.T) { - // Case 1 - twoBig := bigFromBase10("2") - h := *newGFpFromBigInt(twoBig) - twoHex := [4]uint64{0x0000000000000002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000} - w := gfP(twoHex) - - if h != w { - t.Errorf("conversion mismatch: have %s, want %s", h.String(), w.String()) - } - - // Case 2 - pMinus1Big := bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582") - h = *newGFpFromBigInt(pMinus1Big) - pMinus1Hex := [4]uint64{0x3c208c16d87cfd46, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} - w = gfP(pMinus1Hex) - - if h != w { - t.Errorf("conversion mismatch: have %s, want %s", h.String(), w.String()) - } -} - -// Tests the conversion from GFp element to big.Int -func TestGFpToBigInt(t *testing.T) { - // Case 1 - twoHex := [4]uint64{0x0000000000000002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000} - twoBig := bigFromBase10("2") - twoGFp := gfP(twoHex) // Not MontEncoded! - w := twoBig - h, err := twoGFp.gFpToBigInt() - - if err != nil { - t.Errorf("Couldn't convert GFp to big.Int: %s", err) - } - - if r := h.Cmp(w); r != 0 { - t.Errorf("conversion mismatch: have %s, want %s", h.String(), w.String()) - } - - // Case 2 - pMinus1Hex := [4]uint64{0x3c208c16d87cfd46, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} - pMinus1Big := bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582") - pMinus1GFp := gfP(pMinus1Hex) // Not MontEncoded! - w = pMinus1Big - h, err = pMinus1GFp.gFpToBigInt() - - if err != nil { - t.Errorf("Couldn't convert GFp to big.Int: %s", err) - } - - if r := h.Cmp(w); r != 0 { - t.Errorf("conversion mismatch: have %s, want %s", h.String(), w.String()) - } -} diff --git a/crypto/bn256/go.mod b/crypto/bn256/go.mod deleted file mode 100644 index 53b5837..0000000 --- a/crypto/bn256/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/clearmatics/bn256 - -go 1.12 - -require ( - github.com/stretchr/testify v1.3.0 - golang.org/x/sys v0.0.0-20190516110030-61b9204099cb -) diff --git a/crypto/bn256/go.sum b/crypto/bn256/go.sum deleted file mode 100644 index 678c78b..0000000 --- a/crypto/bn256/go.sum +++ /dev/null @@ -1,9 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -golang.org/x/sys v0.0.0-20190516110030-61b9204099cb h1:k07iPOt0d6nEnwXF+kHB+iEg+WSuKe/SOQuFM2QoD+E= -golang.org/x/sys v0.0.0-20190516110030-61b9204099cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/crypto/bn256/lattice.go b/crypto/bn256/lattice.go deleted file mode 100644 index f9ace4d..0000000 --- a/crypto/bn256/lattice.go +++ /dev/null @@ -1,115 +0,0 @@ -package bn256 - -import ( - "math/big" -) - -var half = new(big.Int).Rsh(Order, 1) - -var curveLattice = &lattice{ - vectors: [][]*big.Int{ - {bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")}, - {bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")}, - }, - inverse: []*big.Int{ - bigFromBase10("147946756881789318990833708069417712965"), - bigFromBase10("147946756881789319010696353538189108491"), - }, - det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"), -} - -var targetLattice = &lattice{ - vectors: [][]*big.Int{ - {bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")}, - {bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")}, - {bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")}, - {bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")}, - }, - inverse: []*big.Int{ - bigFromBase10("734653495049373973658254490726798021314063399421879442165"), - bigFromBase10("147946756881789319000765030803803410728"), - bigFromBase10("-147946756881789319005730692170996259609"), - bigFromBase10("1469306990098747947464455738335385361643788813749140841702"), - }, - det: new(big.Int).Set(Order), -} - -type lattice struct { - vectors [][]*big.Int - inverse []*big.Int - det *big.Int -} - -// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis. -func (l *lattice) decompose(k *big.Int) []*big.Int { - n := len(l.inverse) - - // Calculate closest vector in lattice to with Babai's rounding. - c := make([]*big.Int, n) - for i := 0; i < n; i++ { - c[i] = new(big.Int).Mul(k, l.inverse[i]) - round(c[i], l.det) - } - - // Transform vectors according to c and subtract . - out := make([]*big.Int, n) - temp := new(big.Int) - - for i := 0; i < n; i++ { - out[i] = new(big.Int) - - for j := 0; j < n; j++ { - temp.Mul(c[j], l.vectors[j][i]) - out[i].Add(out[i], temp) - } - - out[i].Neg(out[i]) - out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i]) - } - out[0].Add(out[0], k) - - return out -} - -func (l *lattice) Precompute(add func(i, j uint)) { - n := uint(len(l.vectors)) - total := uint(1) << n - - for i := uint(0); i < n; i++ { - for j := uint(0); j < total; j++ { - if (j>>i)&1 == 1 { - add(i, j) - } - } - } -} - -func (l *lattice) Multi(scalar *big.Int) []uint8 { - decomp := l.decompose(scalar) - - maxLen := 0 - for _, x := range decomp { - if x.BitLen() > maxLen { - maxLen = x.BitLen() - } - } - - out := make([]uint8, maxLen) - for j, x := range decomp { - for i := 0; i < maxLen; i++ { - out[i] += uint8(x.Bit(i)) << uint(j) - } - } - - return out -} - -// round sets num to num/denom rounded to the nearest integer. -func round(num, denom *big.Int) { - r := new(big.Int) - num.DivMod(num, denom, r) - - if r.Cmp(half) == 1 { - num.Add(num, big.NewInt(1)) - } -} diff --git a/crypto/bn256/lattice_test.go b/crypto/bn256/lattice_test.go deleted file mode 100644 index 4d52ad9..0000000 --- a/crypto/bn256/lattice_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package bn256 - -import ( - "crypto/rand" - - "testing" -) - -func TestLatticeReduceCurve(t *testing.T) { - k, _ := rand.Int(rand.Reader, Order) - ks := curveLattice.decompose(k) - - if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 { - t.Fatal("reduction too large") - } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 { - t.Fatal("reduction must be positive") - } -} - -func TestLatticeReduceTarget(t *testing.T) { - k, _ := rand.Int(rand.Reader, Order) - ks := targetLattice.decompose(k) - - if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 { - t.Fatal("reduction too large") - } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 { - t.Fatal("reduction must be positive") - } -} diff --git a/crypto/bn256/main_test.go b/crypto/bn256/main_test.go deleted file mode 100644 index c0c8545..0000000 --- a/crypto/bn256/main_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package bn256 - -import ( - "testing" - - "crypto/rand" -) - -func TestRandomG2Marshal(t *testing.T) { - for i := 0; i < 10; i++ { - n, g2, err := RandomG2(rand.Reader) - if err != nil { - t.Error(err) - continue - } - t.Logf("%v: %x\n", n, g2.Marshal()) - } -} - -func TestPairings(t *testing.T) { - a1 := new(G1).ScalarBaseMult(bigFromBase10("1")) - a2 := new(G1).ScalarBaseMult(bigFromBase10("2")) - a37 := new(G1).ScalarBaseMult(bigFromBase10("37")) - an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) - - b0 := new(G2).ScalarBaseMult(bigFromBase10("0")) - b1 := new(G2).ScalarBaseMult(bigFromBase10("1")) - b2 := new(G2).ScalarBaseMult(bigFromBase10("2")) - b27 := new(G2).ScalarBaseMult(bigFromBase10("27")) - b999 := new(G2).ScalarBaseMult(bigFromBase10("999")) - bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) - - p1 := Pair(a1, b1) - pn1 := Pair(a1, bn1) - np1 := Pair(an1, b1) - if pn1.String() != np1.String() { - t.Error("Pairing mismatch: e(a, -b) != e(-a, b)") - } - if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) { - t.Error("MultiAte check gave false negative!") - } - p0 := new(GT).Add(p1, pn1) - p0_2 := Pair(a1, b0) - if p0.String() != p0_2.String() { - t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1") - } - p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")) - if p0.String() != p0_3.String() { - t.Error("Pairing mismatch: e(a, b) has wrong order") - } - p2 := Pair(a2, b1) - p2_2 := Pair(a1, b2) - p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2")) - if p2.String() != p2_2.String() { - t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)") - } - if p2.String() != p2_3.String() { - t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2") - } - if p2.String() == p1.String() { - t.Error("Pairing is degenerate!") - } - if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) { - t.Error("MultiAte check gave false positive!") - } - p999 := Pair(a37, b27) - p999_2 := Pair(a1, b999) - if p999.String() != p999_2.String() { - t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)") - } -} diff --git a/crypto/bn256/mul_amd64.h b/crypto/bn256/mul_amd64.h deleted file mode 100644 index bab5da8..0000000 --- a/crypto/bn256/mul_amd64.h +++ /dev/null @@ -1,181 +0,0 @@ -#define mul(a0,a1,a2,a3, rb, stack) \ - MOVQ a0, AX \ - MULQ 0+rb \ - MOVQ AX, R8 \ - MOVQ DX, R9 \ - MOVQ a0, AX \ - MULQ 8+rb \ - ADDQ AX, R9 \ - ADCQ $0, DX \ - MOVQ DX, R10 \ - MOVQ a0, AX \ - MULQ 16+rb \ - ADDQ AX, R10 \ - ADCQ $0, DX \ - MOVQ DX, R11 \ - MOVQ a0, AX \ - MULQ 24+rb \ - ADDQ AX, R11 \ - ADCQ $0, DX \ - MOVQ DX, R12 \ - \ - storeBlock(R8,R9,R10,R11, 0+stack) \ - MOVQ R12, 32+stack \ - \ - MOVQ a1, AX \ - MULQ 0+rb \ - MOVQ AX, R8 \ - MOVQ DX, R9 \ - MOVQ a1, AX \ - MULQ 8+rb \ - ADDQ AX, R9 \ - ADCQ $0, DX \ - MOVQ DX, R10 \ - MOVQ a1, AX \ - MULQ 16+rb \ - ADDQ AX, R10 \ - ADCQ $0, DX \ - MOVQ DX, R11 \ - MOVQ a1, AX \ - MULQ 24+rb \ - ADDQ AX, R11 \ - ADCQ $0, DX \ - MOVQ DX, R12 \ - \ - ADDQ 8+stack, R8 \ - ADCQ 16+stack, R9 \ - ADCQ 24+stack, R10 \ - ADCQ 32+stack, R11 \ - ADCQ $0, R12 \ - storeBlock(R8,R9,R10,R11, 8+stack) \ - MOVQ R12, 40+stack \ - \ - MOVQ a2, AX \ - MULQ 0+rb \ - MOVQ AX, R8 \ - MOVQ DX, R9 \ - MOVQ a2, AX \ - MULQ 8+rb \ - ADDQ AX, R9 \ - ADCQ $0, DX \ - MOVQ DX, R10 \ - MOVQ a2, AX \ - MULQ 16+rb \ - ADDQ AX, R10 \ - ADCQ $0, DX \ - MOVQ DX, R11 \ - MOVQ a2, AX \ - MULQ 24+rb \ - ADDQ AX, R11 \ - ADCQ $0, DX \ - MOVQ DX, R12 \ - \ - ADDQ 16+stack, R8 \ - ADCQ 24+stack, R9 \ - ADCQ 32+stack, R10 \ - ADCQ 40+stack, R11 \ - ADCQ $0, R12 \ - storeBlock(R8,R9,R10,R11, 16+stack) \ - MOVQ R12, 48+stack \ - \ - MOVQ a3, AX \ - MULQ 0+rb \ - MOVQ AX, R8 \ - MOVQ DX, R9 \ - MOVQ a3, AX \ - MULQ 8+rb \ - ADDQ AX, R9 \ - ADCQ $0, DX \ - MOVQ DX, R10 \ - MOVQ a3, AX \ - MULQ 16+rb \ - ADDQ AX, R10 \ - ADCQ $0, DX \ - MOVQ DX, R11 \ - MOVQ a3, AX \ - MULQ 24+rb \ - ADDQ AX, R11 \ - ADCQ $0, DX \ - MOVQ DX, R12 \ - \ - ADDQ 24+stack, R8 \ - ADCQ 32+stack, R9 \ - ADCQ 40+stack, R10 \ - ADCQ 48+stack, R11 \ - ADCQ $0, R12 \ - storeBlock(R8,R9,R10,R11, 24+stack) \ - MOVQ R12, 56+stack - -#define gfpReduce(stack) \ - \ // m = (T * N') mod R, store m in R8:R9:R10:R11 - MOVQ ·np+0(SB), AX \ - MULQ 0+stack \ - MOVQ AX, R8 \ - MOVQ DX, R9 \ - MOVQ ·np+0(SB), AX \ - MULQ 8+stack \ - ADDQ AX, R9 \ - ADCQ $0, DX \ - MOVQ DX, R10 \ - MOVQ ·np+0(SB), AX \ - MULQ 16+stack \ - ADDQ AX, R10 \ - ADCQ $0, DX \ - MOVQ DX, R11 \ - MOVQ ·np+0(SB), AX \ - MULQ 24+stack \ - ADDQ AX, R11 \ - \ - MOVQ ·np+8(SB), AX \ - MULQ 0+stack \ - MOVQ AX, R12 \ - MOVQ DX, R13 \ - MOVQ ·np+8(SB), AX \ - MULQ 8+stack \ - ADDQ AX, R13 \ - ADCQ $0, DX \ - MOVQ DX, R14 \ - MOVQ ·np+8(SB), AX \ - MULQ 16+stack \ - ADDQ AX, R14 \ - \ - ADDQ R12, R9 \ - ADCQ R13, R10 \ - ADCQ R14, R11 \ - \ - MOVQ ·np+16(SB), AX \ - MULQ 0+stack \ - MOVQ AX, R12 \ - MOVQ DX, R13 \ - MOVQ ·np+16(SB), AX \ - MULQ 8+stack \ - ADDQ AX, R13 \ - \ - ADDQ R12, R10 \ - ADCQ R13, R11 \ - \ - MOVQ ·np+24(SB), AX \ - MULQ 0+stack \ - ADDQ AX, R11 \ - \ - storeBlock(R8,R9,R10,R11, 64+stack) \ - \ - \ // m * N - mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \ - \ - \ // Add the 512-bit intermediate to m*N - loadBlock(96+stack, R8,R9,R10,R11) \ - loadBlock(128+stack, R12,R13,R14,R15) \ - \ - MOVQ $0, AX \ - ADDQ 0+stack, R8 \ - ADCQ 8+stack, R9 \ - ADCQ 16+stack, R10 \ - ADCQ 24+stack, R11 \ - ADCQ 32+stack, R12 \ - ADCQ 40+stack, R13 \ - ADCQ 48+stack, R14 \ - ADCQ 56+stack, R15 \ - ADCQ $0, AX \ - \ - gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX) diff --git a/crypto/bn256/mul_arm64.h b/crypto/bn256/mul_arm64.h deleted file mode 100644 index d405eb8..0000000 --- a/crypto/bn256/mul_arm64.h +++ /dev/null @@ -1,133 +0,0 @@ -#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \ - MUL R1, R5, c0 \ - UMULH R1, R5, c1 \ - MUL R1, R6, R0 \ - ADDS R0, c1 \ - UMULH R1, R6, c2 \ - MUL R1, R7, R0 \ - ADCS R0, c2 \ - UMULH R1, R7, c3 \ - MUL R1, R8, R0 \ - ADCS R0, c3 \ - UMULH R1, R8, c4 \ - ADCS ZR, c4 \ - \ - MUL R2, R5, R1 \ - UMULH R2, R5, R26 \ - MUL R2, R6, R0 \ - ADDS R0, R26 \ - UMULH R2, R6, R27 \ - MUL R2, R7, R0 \ - ADCS R0, R27 \ - UMULH R2, R7, R29 \ - MUL R2, R8, R0 \ - ADCS R0, R29 \ - UMULH R2, R8, c5 \ - ADCS ZR, c5 \ - ADDS R1, c1 \ - ADCS R26, c2 \ - ADCS R27, c3 \ - ADCS R29, c4 \ - ADCS ZR, c5 \ - \ - MUL R3, R5, R1 \ - UMULH R3, R5, R26 \ - MUL R3, R6, R0 \ - ADDS R0, R26 \ - UMULH R3, R6, R27 \ - MUL R3, R7, R0 \ - ADCS R0, R27 \ - UMULH R3, R7, R29 \ - MUL R3, R8, R0 \ - ADCS R0, R29 \ - UMULH R3, R8, c6 \ - ADCS ZR, c6 \ - ADDS R1, c2 \ - ADCS R26, c3 \ - ADCS R27, c4 \ - ADCS R29, c5 \ - ADCS ZR, c6 \ - \ - MUL R4, R5, R1 \ - UMULH R4, R5, R26 \ - MUL R4, R6, R0 \ - ADDS R0, R26 \ - UMULH R4, R6, R27 \ - MUL R4, R7, R0 \ - ADCS R0, R27 \ - UMULH R4, R7, R29 \ - MUL R4, R8, R0 \ - ADCS R0, R29 \ - UMULH R4, R8, c7 \ - ADCS ZR, c7 \ - ADDS R1, c3 \ - ADCS R26, c4 \ - ADCS R27, c5 \ - ADCS R29, c6 \ - ADCS ZR, c7 - -#define gfpReduce() \ - \ // m = (T * N') mod R, store m in R1:R2:R3:R4 - MOVD ·np+0(SB), R17 \ - MOVD ·np+8(SB), R25 \ - MOVD ·np+16(SB), R19 \ - MOVD ·np+24(SB), R20 \ - \ - MUL R9, R17, R1 \ - UMULH R9, R17, R2 \ - MUL R9, R25, R0 \ - ADDS R0, R2 \ - UMULH R9, R25, R3 \ - MUL R9, R19, R0 \ - ADCS R0, R3 \ - UMULH R9, R19, R4 \ - MUL R9, R20, R0 \ - ADCS R0, R4 \ - \ - MUL R10, R17, R21 \ - UMULH R10, R17, R22 \ - MUL R10, R25, R0 \ - ADDS R0, R22 \ - UMULH R10, R25, R23 \ - MUL R10, R19, R0 \ - ADCS R0, R23 \ - ADDS R21, R2 \ - ADCS R22, R3 \ - ADCS R23, R4 \ - \ - MUL R11, R17, R21 \ - UMULH R11, R17, R22 \ - MUL R11, R25, R0 \ - ADDS R0, R22 \ - ADDS R21, R3 \ - ADCS R22, R4 \ - \ - MUL R12, R17, R21 \ - ADDS R21, R4 \ - \ - \ // m * N - loadModulus(R5,R6,R7,R8) \ - mul(R17,R25,R19,R20,R21,R22,R23,R24) \ - \ - \ // Add the 512-bit intermediate to m*N - MOVD ZR, R0 \ - ADDS R9, R17 \ - ADCS R10, R25 \ - ADCS R11, R19 \ - ADCS R12, R20 \ - ADCS R13, R21 \ - ADCS R14, R22 \ - ADCS R15, R23 \ - ADCS R16, R24 \ - ADCS ZR, R0 \ - \ - \ // Our output is R21:R22:R23:R24. Reduce mod p if necessary. - SUBS R5, R21, R10 \ - SBCS R6, R22, R11 \ - SBCS R7, R23, R12 \ - SBCS R8, R24, R13 \ - \ - CSEL CS, R10, R21, R1 \ - CSEL CS, R11, R22, R2 \ - CSEL CS, R12, R23, R3 \ - CSEL CS, R13, R24, R4 diff --git a/crypto/bn256/mul_bmi2_amd64.h b/crypto/bn256/mul_bmi2_amd64.h deleted file mode 100644 index 71ad049..0000000 --- a/crypto/bn256/mul_bmi2_amd64.h +++ /dev/null @@ -1,112 +0,0 @@ -#define mulBMI2(a0,a1,a2,a3, rb) \ - MOVQ a0, DX \ - MOVQ $0, R13 \ - MULXQ 0+rb, R8, R9 \ - MULXQ 8+rb, AX, R10 \ - ADDQ AX, R9 \ - MULXQ 16+rb, AX, R11 \ - ADCQ AX, R10 \ - MULXQ 24+rb, AX, R12 \ - ADCQ AX, R11 \ - ADCQ $0, R12 \ - ADCQ $0, R13 \ - \ - MOVQ a1, DX \ - MOVQ $0, R14 \ - MULXQ 0+rb, AX, BX \ - ADDQ AX, R9 \ - ADCQ BX, R10 \ - MULXQ 16+rb, AX, BX \ - ADCQ AX, R11 \ - ADCQ BX, R12 \ - ADCQ $0, R13 \ - MULXQ 8+rb, AX, BX \ - ADDQ AX, R10 \ - ADCQ BX, R11 \ - MULXQ 24+rb, AX, BX \ - ADCQ AX, R12 \ - ADCQ BX, R13 \ - ADCQ $0, R14 \ - \ - MOVQ a2, DX \ - MOVQ $0, R15 \ - MULXQ 0+rb, AX, BX \ - ADDQ AX, R10 \ - ADCQ BX, R11 \ - MULXQ 16+rb, AX, BX \ - ADCQ AX, R12 \ - ADCQ BX, R13 \ - ADCQ $0, R14 \ - MULXQ 8+rb, AX, BX \ - ADDQ AX, R11 \ - ADCQ BX, R12 \ - MULXQ 24+rb, AX, BX \ - ADCQ AX, R13 \ - ADCQ BX, R14 \ - ADCQ $0, R15 \ - \ - MOVQ a3, DX \ - MULXQ 0+rb, AX, BX \ - ADDQ AX, R11 \ - ADCQ BX, R12 \ - MULXQ 16+rb, AX, BX \ - ADCQ AX, R13 \ - ADCQ BX, R14 \ - ADCQ $0, R15 \ - MULXQ 8+rb, AX, BX \ - ADDQ AX, R12 \ - ADCQ BX, R13 \ - MULXQ 24+rb, AX, BX \ - ADCQ AX, R14 \ - ADCQ BX, R15 - -#define gfpReduceBMI2() \ - \ // m = (T * N') mod R, store m in R8:R9:R10:R11 - MOVQ ·np+0(SB), DX \ - MULXQ 0(SP), R8, R9 \ - MULXQ 8(SP), AX, R10 \ - ADDQ AX, R9 \ - MULXQ 16(SP), AX, R11 \ - ADCQ AX, R10 \ - MULXQ 24(SP), AX, BX \ - ADCQ AX, R11 \ - \ - MOVQ ·np+8(SB), DX \ - MULXQ 0(SP), AX, BX \ - ADDQ AX, R9 \ - ADCQ BX, R10 \ - MULXQ 16(SP), AX, BX \ - ADCQ AX, R11 \ - MULXQ 8(SP), AX, BX \ - ADDQ AX, R10 \ - ADCQ BX, R11 \ - \ - MOVQ ·np+16(SB), DX \ - MULXQ 0(SP), AX, BX \ - ADDQ AX, R10 \ - ADCQ BX, R11 \ - MULXQ 8(SP), AX, BX \ - ADDQ AX, R11 \ - \ - MOVQ ·np+24(SB), DX \ - MULXQ 0(SP), AX, BX \ - ADDQ AX, R11 \ - \ - storeBlock(R8,R9,R10,R11, 64(SP)) \ - \ - \ // m * N - mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \ - \ - \ // Add the 512-bit intermediate to m*N - MOVQ $0, AX \ - ADDQ 0(SP), R8 \ - ADCQ 8(SP), R9 \ - ADCQ 16(SP), R10 \ - ADCQ 24(SP), R11 \ - ADCQ 32(SP), R12 \ - ADCQ 40(SP), R13 \ - ADCQ 48(SP), R14 \ - ADCQ 56(SP), R15 \ - ADCQ $0, AX \ - \ - gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX) diff --git a/crypto/bn256/optate.go b/crypto/bn256/optate.go deleted file mode 100644 index b71e50e..0000000 --- a/crypto/bn256/optate.go +++ /dev/null @@ -1,271 +0,0 @@ -package bn256 - -func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) { - // See the mixed addition algorithm from "Faster Computation of the - // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf - B := (&gfP2{}).Mul(&p.x, &r.t) - - D := (&gfP2{}).Add(&p.y, &r.z) - D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) - - H := (&gfP2{}).Sub(B, &r.x) - I := (&gfP2{}).Square(H) - - E := (&gfP2{}).Add(I, I) - E.Add(E, E) - - J := (&gfP2{}).Mul(H, E) - - L1 := (&gfP2{}).Sub(D, &r.y) - L1.Sub(L1, &r.y) - - V := (&gfP2{}).Mul(&r.x, E) - - rOut = &twistPoint{} - rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) - - rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I) - - t := (&gfP2{}).Sub(V, &rOut.x) - t.Mul(t, L1) - t2 := (&gfP2{}).Mul(&r.y, J) - t2.Add(t2, t2) - rOut.y.Sub(t, t2) - - rOut.t.Square(&rOut.z) - - t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t) - - t2.Mul(L1, &p.x) - t2.Add(t2, t2) - a = (&gfP2{}).Sub(t2, t) - - c = (&gfP2{}).MulScalar(&rOut.z, &q.y) - c.Add(c, c) - - b = (&gfP2{}).Neg(L1) - b.MulScalar(b, &q.x).Add(b, b) - - return -} - -func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) { - // See the doubling algorithm for a=0 from "Faster Computation of the - // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf - A := (&gfP2{}).Square(&r.x) - B := (&gfP2{}).Square(&r.y) - C := (&gfP2{}).Square(B) - - D := (&gfP2{}).Add(&r.x, B) - D.Square(D).Sub(D, A).Sub(D, C).Add(D, D) - - E := (&gfP2{}).Add(A, A) - E.Add(E, A) - - G := (&gfP2{}).Square(E) - - rOut = &twistPoint{} - rOut.x.Sub(G, D).Sub(&rOut.x, D) - - rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t) - - rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E) - t := (&gfP2{}).Add(C, C) - t.Add(t, t).Add(t, t) - rOut.y.Sub(&rOut.y, t) - - rOut.t.Square(&rOut.z) - - t.Mul(E, &r.t).Add(t, t) - b = (&gfP2{}).Neg(t) - b.MulScalar(b, &q.x) - - a = (&gfP2{}).Add(&r.x, E) - a.Square(a).Sub(a, A).Sub(a, G) - t.Add(B, B).Add(t, t) - a.Sub(a, t) - - c = (&gfP2{}).Mul(&rOut.z, &r.t) - c.Add(c, c).MulScalar(c, &q.y) - - return -} - -func mulLine(ret *gfP12, a, b, c *gfP2) { - a2 := &gfP6{} - a2.y.Set(a) - a2.z.Set(b) - a2.Mul(a2, &ret.x) - t3 := (&gfP6{}).MulScalar(&ret.y, c) - - t := (&gfP2{}).Add(b, c) - t2 := &gfP6{} - t2.y.Set(a) - t2.z.Set(t) - ret.x.Add(&ret.x, &ret.y) - - ret.y.Set(t3) - - ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y) - a2.MulTau(a2) - ret.y.Add(&ret.y, a2) -} - -// sixuPlus2NAF is 6u+2 in non-adjacent form. -var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, - 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, - 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, - 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1} - -// miller implements the Miller loop for calculating the Optimal Ate pairing. -// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf -func miller(q *twistPoint, p *curvePoint) *gfP12 { - ret := (&gfP12{}).SetOne() - - aAffine := &twistPoint{} - aAffine.Set(q) - aAffine.MakeAffine() - - bAffine := &curvePoint{} - bAffine.Set(p) - bAffine.MakeAffine() - - minusA := &twistPoint{} - minusA.Neg(aAffine) - - r := &twistPoint{} - r.Set(aAffine) - - r2 := (&gfP2{}).Square(&aAffine.y) - - for i := len(sixuPlus2NAF) - 1; i > 0; i-- { - a, b, c, newR := lineFunctionDouble(r, bAffine) - if i != len(sixuPlus2NAF)-1 { - ret.Square(ret) - } - - mulLine(ret, a, b, c) - r = newR - - switch sixuPlus2NAF[i-1] { - case 1: - a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2) - case -1: - a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2) - default: - continue - } - - mulLine(ret, a, b, c) - r = newR - } - - // In order to calculate Q1 we have to convert q from the sextic twist - // to the full GF(p^12) group, apply the Frobenius there, and convert - // back. - // - // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just - // x for a moment, then after applying the Frobenius, we have x̄ω^(2p) - // where x̄ is the conjugate of x. If we are going to apply the inverse - // isomorphism we need a value with a single coefficient of ω² so we - // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of - // p, 2p-2 is a multiple of six. Therefore we can rewrite as - // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the - // ω². - // - // A similar argument can be made for the y value. - - q1 := &twistPoint{} - q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3) - q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2) - q1.z.SetOne() - q1.t.SetOne() - - // For Q2 we are applying the p² Frobenius. The two conjugations cancel - // out and we are left only with the factors from the isomorphism. In - // the case of x, we end up with a pure number which is why - // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We - // ignore this to end up with -Q2. - - minusQ2 := &twistPoint{} - minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3) - minusQ2.y.Set(&aAffine.y) - minusQ2.z.SetOne() - minusQ2.t.SetOne() - - r2.Square(&q1.y) - a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2) - mulLine(ret, a, b, c) - r = newR - - r2.Square(&minusQ2.y) - a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2) - mulLine(ret, a, b, c) - r = newR - - return ret -} - -// finalExponentiation computes the (p¹²-1)/Order-th power of an element of -// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from -// http://cryptojedi.org/papers/dclxvi-20100714.pdf) -func finalExponentiation(in *gfP12) *gfP12 { - t1 := &gfP12{} - - // This is the p^6-Frobenius - t1.x.Neg(&in.x) - t1.y.Set(&in.y) - - inv := &gfP12{} - inv.Invert(in) - t1.Mul(t1, inv) - - t2 := (&gfP12{}).FrobeniusP2(t1) - t1.Mul(t1, t2) - - fp := (&gfP12{}).Frobenius(t1) - fp2 := (&gfP12{}).FrobeniusP2(t1) - fp3 := (&gfP12{}).Frobenius(fp2) - - fu := (&gfP12{}).Exp(t1, u) - fu2 := (&gfP12{}).Exp(fu, u) - fu3 := (&gfP12{}).Exp(fu2, u) - - y3 := (&gfP12{}).Frobenius(fu) - fu2p := (&gfP12{}).Frobenius(fu2) - fu3p := (&gfP12{}).Frobenius(fu3) - y2 := (&gfP12{}).FrobeniusP2(fu2) - - y0 := &gfP12{} - y0.Mul(fp, fp2).Mul(y0, fp3) - - y1 := (&gfP12{}).Conjugate(t1) - y5 := (&gfP12{}).Conjugate(fu2) - y3.Conjugate(y3) - y4 := (&gfP12{}).Mul(fu, fu2p) - y4.Conjugate(y4) - - y6 := (&gfP12{}).Mul(fu3, fu3p) - y6.Conjugate(y6) - - t0 := (&gfP12{}).Square(y6) - t0.Mul(t0, y4).Mul(t0, y5) - t1.Mul(y3, y5).Mul(t1, t0) - t0.Mul(t0, y2) - t1.Square(t1).Mul(t1, t0).Square(t1) - t0.Mul(t1, y1) - t1.Mul(t1, y0) - t0.Square(t0).Mul(t0, t1) - - return t0 -} - -func optimalAte(a *twistPoint, b *curvePoint) *gfP12 { - e := miller(a, b) - ret := finalExponentiation(e) - - if a.IsInfinity() || b.IsInfinity() { - ret.SetOne() - } - return ret -} diff --git a/crypto/bn256/twist.go b/crypto/bn256/twist.go deleted file mode 100644 index 865a930..0000000 --- a/crypto/bn256/twist.go +++ /dev/null @@ -1,217 +0,0 @@ -package bn256 - -import ( - "math/big" -) - -// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are -// kept in Jacobian form and t=z² when valid. The group G₂ is the set of -// n-torsion points of this curve over GF(p²) (where n = Order) -type twistPoint struct { - x, y, z, t gfP2 -} - -// -// btwist = 3 / Fp2(i + 9); btwist -// # 266929791119991161246907387137283842545076965332900288569378510910307636690*i + 19485874751759354771024239261021720505790618469301721065564631296452457478373 -// hex(266929791119991161246907387137283842545076965332900288569378510910307636690) -// # 009713b03af0fed4 cd2cafadeed8fdf4 a74fa084e52d1852 e4a2bd0685c315d2 -// hex(19485874751759354771024239261021720505790618469301721065564631296452457478373) -// # 2b149d40ceb8aaae 81be18991be06ac3 b5b4c5e559dbefa3 3267e6dc24a138e5 -// <\sage> -// -// c0 = 19485874751759354771024239261021720505790618469301721065564631296452457478373 -// c1 = 266929791119991161246907387137283842545076965332900288569378510910307636690 -// -// twistB is the montgomery encoding of the btwist obtained above -var twistB = &gfP2{ - gfP{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d}, - gfP{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d}, -} - -// twistGen is the generator of group G₂. -var twistGen = &twistPoint{ - gfP2{ - gfP{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b}, - gfP{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b}, - }, - gfP2{ - gfP{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482}, - gfP{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206}, - }, - gfP2{*newGFp(0), *newGFp(1)}, - gfP2{*newGFp(0), *newGFp(1)}, -} - -func (c *twistPoint) String() string { - c.MakeAffine() - x, y := gfP2Decode(&c.x), gfP2Decode(&c.y) - return "(" + x.String() + ", " + y.String() + ")" -} - -func (c *twistPoint) Set(a *twistPoint) { - c.x.Set(&a.x) - c.y.Set(&a.y) - c.z.Set(&a.z) - c.t.Set(&a.t) -} - -// IsOnCurve returns true iff c is on the curve. -func (c *twistPoint) IsOnCurve() bool { - c.MakeAffine() - if c.IsInfinity() { - return true - } - - y2, x3 := &gfP2{}, &gfP2{} - y2.Square(&c.y) - x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB) - - if *y2 != *x3 { - return false - } - cneg := &twistPoint{} - cneg.Mul(c, Order) - return cneg.z.IsZero() -} - -func (c *twistPoint) SetInfinity() { - c.x.SetZero() - c.y.SetOne() - c.z.SetZero() - c.t.SetZero() -} - -func (c *twistPoint) IsInfinity() bool { - return c.z.IsZero() -} - -func (c *twistPoint) Add(a, b *twistPoint) { - // For additional comments, see the same function in curve.go. - - if a.IsInfinity() { - c.Set(b) - return - } - if b.IsInfinity() { - c.Set(a) - return - } - - // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 - z12 := (&gfP2{}).Square(&a.z) - z22 := (&gfP2{}).Square(&b.z) - u1 := (&gfP2{}).Mul(&a.x, z22) - u2 := (&gfP2{}).Mul(&b.x, z12) - - t := (&gfP2{}).Mul(&b.z, z22) - s1 := (&gfP2{}).Mul(&a.y, t) - - t.Mul(&a.z, z12) - s2 := (&gfP2{}).Mul(&b.y, t) - - h := (&gfP2{}).Sub(u2, u1) - xEqual := h.IsZero() - - t.Add(h, h) - i := (&gfP2{}).Square(t) - j := (&gfP2{}).Mul(h, i) - - t.Sub(s2, s1) - yEqual := t.IsZero() - if xEqual && yEqual { - c.Double(a) - return - } - r := (&gfP2{}).Add(t, t) - - v := (&gfP2{}).Mul(u1, i) - - t4 := (&gfP2{}).Square(r) - t.Add(v, v) - t6 := (&gfP2{}).Sub(t4, j) - c.x.Sub(t6, t) - - t.Sub(v, &c.x) // t7 - t4.Mul(s1, j) // t8 - t6.Add(t4, t4) // t9 - t4.Mul(r, t) // t10 - c.y.Sub(t4, t6) - - t.Add(&a.z, &b.z) // t11 - t4.Square(t) // t12 - t.Sub(t4, z12) // t13 - t4.Sub(t, z22) // t14 - c.z.Mul(t4, h) -} - -func (c *twistPoint) Double(a *twistPoint) { - // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 - A := (&gfP2{}).Square(&a.x) - B := (&gfP2{}).Square(&a.y) - C := (&gfP2{}).Square(B) - - t := (&gfP2{}).Add(&a.x, B) - t2 := (&gfP2{}).Square(t) - t.Sub(t2, A) - t2.Sub(t, C) - d := (&gfP2{}).Add(t2, t2) - t.Add(A, A) - e := (&gfP2{}).Add(t, A) - f := (&gfP2{}).Square(e) - - t.Add(d, d) - c.x.Sub(f, t) - - t.Add(C, C) - t2.Add(t, t) - t.Add(t2, t2) - c.y.Sub(d, &c.x) - t2.Mul(e, &c.y) - c.y.Sub(t2, t) - - t.Mul(&a.y, &a.z) - c.z.Add(t, t) -} - -func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) { - sum, t := &twistPoint{}, &twistPoint{} - - for i := scalar.BitLen(); i >= 0; i-- { - t.Double(sum) - if scalar.Bit(i) != 0 { - sum.Add(t, a) - } else { - sum.Set(t) - } - } - - c.Set(sum) -} - -func (c *twistPoint) MakeAffine() { - if c.z.IsOne() { - return - } else if c.z.IsZero() { - c.x.SetZero() - c.y.SetOne() - c.t.SetZero() - return - } - - zInv := (&gfP2{}).Invert(&c.z) - t := (&gfP2{}).Mul(&c.y, zInv) - zInv2 := (&gfP2{}).Square(zInv) - c.y.Mul(t, zInv2) - t.Mul(&c.x, zInv2) - c.x.Set(t) - c.z.SetOne() - c.t.SetOne() -} - -func (c *twistPoint) Neg(a *twistPoint) { - c.x.Set(&a.x) - c.y.Neg(&a.y) - c.z.Set(&a.z) - c.t.SetZero() -} diff --git a/crypto/bnred.go b/crypto/bnred.go deleted file mode 100644 index 1e22b16..0000000 --- a/crypto/bnred.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "math/big" - -//import "encoding/binary" - -//import "crypto/rand" -//import "github.com/deroproject/derohe/crypto/bn256" - -// this file implements Big Number Reduced form with bn256's Order - -type BNRed big.Int - -func RandomScalarBNRed() *BNRed { - return (*BNRed)(RandomScalar()) -} - -// converts big.Int to BNRed -func GetBNRed(x *big.Int) *BNRed { - result := new(BNRed) - - ((*big.Int)(result)).Set(x) - return result -} - -// convert BNRed to BigInt -func (x *BNRed) BigInt() *big.Int { - return new(big.Int).Set(((*big.Int)(x))) -} - -func (x *BNRed) SetBytes(buf []byte) *BNRed { - ((*big.Int)(x)).SetBytes(buf) - return x -} - -func (x *BNRed) String() string { - return ((*big.Int)(x)).Text(16) -} - -func (x *BNRed) Text(base int) string { - return ((*big.Int)(x)).Text(base) -} - -func (x *BNRed) MarshalText() ([]byte, error) { - return []byte(((*big.Int)(x)).Text(16)), nil -} - -func (x *BNRed) UnmarshalText(text []byte) error { - _, err := fmt.Sscan("0x"+string(text), ((*big.Int)(x))) - return err -} - -func FillBytes(x *big.Int, xbytes []byte) { - // FillBytes not available pre 1.15 - bb := x.Bytes() - - if len(bb) > 32 { - panic(fmt.Sprintf("number not representable in 32 bytes %d %x", len(bb), bb)) - } - - for i := range xbytes { // optimized to memclr - xbytes[i] = 0 - } - - j := 32 - for i := len(bb) - 1; i >= 0; i-- { - j-- - xbytes[j] = bb[i] - } -} - -/* -// this will return fixed random scalar -func RandomScalarFixed() *big.Int { - //return new(big.Int).Set(fixed) - - return RandomScalar() -} - - -type KeyPair struct { - x *big.Int // secret key - y *bn256.G1 // public key -} -*/ diff --git a/crypto/const.go b/crypto/const.go deleted file mode 100644 index a0deb40..0000000 --- a/crypto/const.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" - -const POINT_SIZE = 33 // this can be optimized to 33 bytes -const FIELDELEMENT_SIZE = 32 // why not have bigger curves - -// protocol supports amounts upto this amounts -const MAX_AMOUNT = 18446744073709551616 // 2^64 - 1, - -const PROTOCOL_CONSTANT = "DERO" - -// checks a number is power of 2 -func IsPowerOf2(num int) bool { - for num >= 2 { - if num%2 != 0 { - return false - } - num = num / 2 - } - return num == 1 -} - -// tell what power a number is -func GetPowerof2(num int) int { - - if num <= 0 { - panic("number cannot be less than 0") - } - - if !IsPowerOf2(num) { - panic(fmt.Sprintf("number(%d) must be power of 2", num)) - } - - power := 0 - calculated := 1 - for ; calculated != num; power++ { - calculated *= 2 - } - return power -} diff --git a/crypto/fieldvector.go b/crypto/fieldvector.go deleted file mode 100644 index acfd92a..0000000 --- a/crypto/fieldvector.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -type FieldVectorPolynomial struct { - coefficients []*FieldVector -} - -func NewFieldVectorPolynomial(inputs ...*FieldVector) *FieldVectorPolynomial { - fv := &FieldVectorPolynomial{} - for _, input := range inputs { - fv.coefficients = append(fv.coefficients, input.Clone()) - } - return fv -} - -func (fv *FieldVectorPolynomial) Length() int { - return len(fv.coefficients) -} - -func (fv *FieldVectorPolynomial) Evaluate(x *big.Int) *FieldVector { - - result := fv.coefficients[0].Clone() - - accumulator := new(big.Int).Set(x) - - for i := 1; i < len(fv.coefficients); i++ { - result = result.Add(fv.coefficients[i].Times(accumulator)) - accumulator.Mul(accumulator, x) - accumulator.Mod(accumulator, bn256.Order) - - } - return result -} - -func (fv *FieldVectorPolynomial) InnerProduct(other *FieldVectorPolynomial) []*big.Int { - - var result []*big.Int - - result_length := fv.Length() + other.Length() - 1 - for i := 0; i < result_length; i++ { - result = append(result, new(big.Int)) // 0 value fill - } - - for i := range fv.coefficients { - for j := range other.coefficients { - tmp := new(big.Int).Set(result[i+j]) - result[i+j].Add(tmp, fv.coefficients[i].InnerProduct(other.coefficients[j])) - result[i+j].Mod(result[i+j], bn256.Order) - } - } - return result -} - -/* - -type PedersenCommitment struct { - X *big.Int - R *big.Int - Params *GeneratorParams -} - -func NewPedersenCommitment(params *GeneratorParams, x, r *big.Int) *PedersenCommitment { - pc := &PedersenCommitment{Params: params, X: new(big.Int).Set(x), R: new(big.Int).Set(r)} - return pc -} -func (pc *PedersenCommitment) Commit() *bn256.G1 { - var left, right, result bn256.G1 - left.ScalarMult(pc.Params.G, pc.X) - right.ScalarMult(pc.Params.H, pc.R) - result.Add(&left, &right) - return &result -} -func (pc *PedersenCommitment) Add(other *PedersenCommitment) *PedersenCommitment { - var x, r big.Int - x.Mod(new(big.Int).Add(pc.X, other.X), bn256.Order) - r.Mod(new(big.Int).Add(pc.R, other.R), bn256.Order) - return NewPedersenCommitment(pc.Params, &x, &r) -} -func (pc *PedersenCommitment) Times(constant *big.Int) *PedersenCommitment { - var x, r big.Int - x.Mod(new(big.Int).Mul(pc.X, constant), bn256.Order) - r.Mod(new(big.Int).Mul(pc.R, constant), bn256.Order) - return NewPedersenCommitment(pc.Params, &x, &r) -} - -type PolyCommitment struct { - coefficient_commitments []*PedersenCommitment - Params *GeneratorParams -} - -func NewPolyCommitment(params *GeneratorParams, coefficients []*big.Int) *PolyCommitment { - pc := &PolyCommitment{Params: params} - pc.coefficient_commitments = append(pc.coefficient_commitments, NewPedersenCommitment(params, coefficients[0], new(big.Int).SetUint64(0))) - - for i := 1; i < len(coefficients); i++ { - pc.coefficient_commitments = append(pc.coefficient_commitments, NewPedersenCommitment(params, coefficients[i], RandomScalarFixed())) - - } - return pc -} - -func (pc *PolyCommitment) GetCommitments() []*bn256.G1 { - var result []*bn256.G1 - for i := 1; i < len(pc.coefficient_commitments); i++ { - result = append(result, pc.coefficient_commitments[i].Commit()) - } - return result -} - -func (pc *PolyCommitment) Evaluate(constant *big.Int) *PedersenCommitment { - result := pc.coefficient_commitments[0] - - accumulator := new(big.Int).Set(constant) - - for i := 1; i < len(pc.coefficient_commitments); i++ { - - tmp := new(big.Int).Set(accumulator) - result = result.Add(pc.coefficient_commitments[i].Times(accumulator)) - accumulator.Mod(new(big.Int).Mul(tmp, constant), bn256.Order) - } - - return result -} -*/ - -/* -// bother FieldVector and GeneratorVector satisfy this -type Vector interface{ - Length() int - Extract(parity bool) Vector - Add(other Vector)Vector - Hadamard( []*big.Int) Vector - Times (*big.Int) Vector - Negate() Vector -} -*/ - -// check this https://pdfs.semanticscholar.org/d38d/e48ee4127205a0f25d61980c8f241718b66e.pdf -// https://arxiv.org/pdf/1802.03932.pdf - -var unity *big.Int - -func init() { - // primitive 2^28th root of unity modulo q - unity, _ = new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd", 16) - -} - -func fft_FieldVector(input *FieldVector, inverse bool) *FieldVector { - length := input.Length() - if length == 1 { - return input - } - - // lngth must be multiple of 2 ToDO - if length%2 != 0 { - panic("length must be multiple of 2") - } - - //unity,_ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd",16) - - omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(length)), bn256.Order) - if inverse { - omega = new(big.Int).ModInverse(omega, bn256.Order) - } - - even := fft_FieldVector(input.Extract(false), inverse) - odd := fft_FieldVector(input.Extract(true), inverse) - - omegas := []*big.Int{new(big.Int).SetUint64(1)} - - for i := 1; i < length/2; i++ { - omegas = append(omegas, new(big.Int).Mod(new(big.Int).Mul(omegas[i-1], omega), bn256.Order)) - } - - omegasv := NewFieldVector(omegas) - result := even.Add(odd.Hadamard(omegasv)).Concat(even.Add(odd.Hadamard(omegasv).Negate())) - if inverse { - result = result.Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)) - } - - return result - -} - -// this is exactly same as fft_FieldVector, alternate implementation -func fftints(input []*big.Int) (result []*big.Int) { - size := len(input) - if size == 1 { - return input - } - //require(size % 2 == 0, "Input size is not a power of 2!"); - - unity, _ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd", 16) - - omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(size)), bn256.Order) - - even := fftints(extractbits(input, 0)) - odd := fftints(extractbits(input, 1)) - omega_run := new(big.Int).SetUint64(1) - result = make([]*big.Int, len(input), len(input)) - for i := 0; i < len(input)/2; i++ { - temp := new(big.Int).Mod(new(big.Int).Mul(odd[i], omega_run), bn256.Order) - result[i] = new(big.Int).Mod(new(big.Int).Add(even[i], temp), bn256.Order) - result[i+size/2] = new(big.Int).Mod(new(big.Int).Sub(even[i], temp), bn256.Order) - omega_run = new(big.Int).Mod(new(big.Int).Mul(omega, omega_run), bn256.Order) - } - return result -} - -func extractbits(input []*big.Int, parity int) (result []*big.Int) { - result = make([]*big.Int, len(input)/2, len(input)/2) - for i := 0; i < len(input)/2; i++ { - result[i] = new(big.Int).Set(input[2*i+parity]) - } - return -} - -func fft_GeneratorVector(input *PointVector, inverse bool) *PointVector { - length := input.Length() - if length == 1 { - return input - } - - // lngth must be multiple of 2 ToDO - if length%2 != 0 { - panic("length must be multiple of 2") - } - - // unity,_ := new(big.Int).SetString("14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd",16) - - omega := new(big.Int).Exp(unity, new(big.Int).SetUint64((1<<28)/uint64(length)), bn256.Order) - if inverse { - omega = new(big.Int).ModInverse(omega, bn256.Order) - } - - even := fft_GeneratorVector(input.Extract(false), inverse) - - //fmt.Printf("exponent_fft %d %s \n",i, exponent_fft.vector[i].Text(16)) - - odd := fft_GeneratorVector(input.Extract(true), inverse) - - omegas := []*big.Int{new(big.Int).SetUint64(1)} - - for i := 1; i < length/2; i++ { - omegas = append(omegas, new(big.Int).Mod(new(big.Int).Mul(omegas[i-1], omega), bn256.Order)) - } - - omegasv := omegas - result := even.Add(odd.Hadamard(omegasv)).Concat(even.Add(odd.Hadamard(omegasv).Negate())) - if inverse { - result = result.Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)) - } - - return result - -} - -func Convolution(exponent *FieldVector, base *PointVector) *PointVector { - size := base.Length() - - exponent_fft := fft_FieldVector(exponent.Flip(), false) - - /*exponent_fft2 := fftints( exponent.Flip().vector) // aternate implementation proof checking - for i := range exponent_fft.vector{ - fmt.Printf("exponent_fft %d %s \n",i, exponent_fft.vector[i].Text(16)) - fmt.Printf("exponent_ff2 %d %s \n",i, exponent_fft2[i].Text(16)) - } - */ - - temp := fft_GeneratorVector(base, false).Hadamard(exponent_fft.vector) - return fft_GeneratorVector(temp.Slice(0, size/2).Add(temp.Slice(size/2, size)).Times(new(big.Int).ModInverse(new(big.Int).SetUint64(2), bn256.Order)), true) - // using the optimization described here https://dsp.stackexchange.com/a/30699 -} diff --git a/crypto/generatorparams.go b/crypto/generatorparams.go deleted file mode 100644 index fb795a8..0000000 --- a/crypto/generatorparams.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -func NewGeneratorParams(count int) *GeneratorParams { - GP := &GeneratorParams{} - var zeroes [64]byte - - GP.G = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "G"))) // this is same as mybase or vice-versa - GP.H = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "H"))) - - var gs, hs []*bn256.G1 - - GP.GSUM = new(bn256.G1) - GP.GSUM.Unmarshal(zeroes[:]) - - for i := 0; i < count; i++ { - gs = append(gs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"G"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) - hs = append(hs, HashToPoint(HashtoNumber(append([]byte(PROTOCOL_CONSTANT+"H"), hextobytes(makestring64(fmt.Sprintf("%x", i)))...)))) - - GP.GSUM = new(bn256.G1).Add(GP.GSUM, gs[i]) - } - GP.Gs = NewPointVector(gs) - GP.Hs = NewPointVector(hs) - - return GP -} - -func NewGeneratorParams3(h *bn256.G1, gs, hs *PointVector) *GeneratorParams { - GP := &GeneratorParams{} - - GP.G = HashToPoint(HashtoNumber([]byte(PROTOCOL_CONSTANT + "G"))) // this is same as mybase or vice-versa - GP.H = h - GP.Gs = gs - GP.Hs = hs - return GP -} - -func (gp *GeneratorParams) Commit(blind *big.Int, gexps, hexps *FieldVector) *bn256.G1 { - result := new(bn256.G1).ScalarMult(gp.H, blind) - for i := range gexps.vector { - result = new(bn256.G1).Add(result, new(bn256.G1).ScalarMult(gp.Gs.vector[i], gexps.vector[i])) - } - if hexps != nil { - for i := range hexps.vector { - result = new(bn256.G1).Add(result, new(bn256.G1).ScalarMult(gp.Hs.vector[i], hexps.vector[i])) - } - } - return result -} diff --git a/crypto/group.go b/crypto/group.go deleted file mode 100644 index 917e12f..0000000 --- a/crypto/group.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" -import "encoding/hex" - -//import "crypto/rand" -import "github.com/deroproject/derohe/crypto/bn256" - -// this file implements Big Number Reduced form with bn256's Order - -type Point bn256.G1 - -var GPoint Point - -// ScalarMult with chainable API -func (p *Point) ScalarMult(r *BNRed) (result *Point) { - result = new(Point) - ((*bn256.G1)(result)).ScalarMult(((*bn256.G1)(p)), ((*big.Int)(r))) - return result -} - -func (p *Point) EncodeCompressed() []byte { - return ((*bn256.G1)(p)).EncodeCompressed() -} - -func (p *Point) DecodeCompressed(i []byte) error { - return ((*bn256.G1)(p)).DecodeCompressed(i) -} - -func (p *Point) G1() *bn256.G1 { - return ((*bn256.G1)(p)) -} -func (p *Point) Set(x *Point) *Point { - return ((*Point)(((*bn256.G1)(p)).Set(((*bn256.G1)(x))))) -} - -func (p *Point) String() string { - return string(p.EncodeCompressed()) -} - -func (p *Point) StringHex() string { - return string(hex.EncodeToString(p.EncodeCompressed())) -} - -func (p *Point) MarshalText() ([]byte, error) { - return []byte(hex.EncodeToString(p.EncodeCompressed())), nil -} - -func (p *Point) UnmarshalText(text []byte) error { - - tmp, err := hex.DecodeString(string(text)) - if err != nil { - return err - } - return p.DecodeCompressed(tmp) -} diff --git a/crypto/hash.go b/crypto/hash.go deleted file mode 100644 index 9881b6f..0000000 --- a/crypto/hash.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "encoding/hex" - -const ( - ChecksumLength = 4 // for addresses - HashLength = 32 -) - -type Hash [HashLength]byte -type Checksum [ChecksumLength]byte - -func (h Hash) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("%x", h[:])), nil -} - -func (h *Hash) UnmarshalText(data []byte) (err error) { - byteSlice, _ := hex.DecodeString(string(data)) - if len(byteSlice) != 32 { - return fmt.Errorf("Incorrect hash size") - } - copy(h[:], byteSlice) - return -} - -// stringifier -func (h Hash) String() string { - return fmt.Sprintf("%x", h[:]) -} - -// convert a hash of hex form to binary form, returns a zero hash if any error -// TODO this should be in crypto -func HashHexToHash(hash_hex string) (hash Hash) { - hash_raw, err := hex.DecodeString(hash_hex) - - if err != nil { - //panic(fmt.Sprintf("Cannot hex decode checkpint hash \"%s\"", hash_hex)) - return hash - } - - if len(hash_raw) != 32 { - //panic(fmt.Sprintf(" hash not 32 byte size Cannot hex decode checkpint hash \"%s\"", hash_hex)) - return hash - } - - copy(hash[:], hash_raw) - return -} diff --git a/crypto/hashtopoint.go b/crypto/hashtopoint.go deleted file mode 100644 index 1e8f3cb..0000000 --- a/crypto/hashtopoint.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "math/big" - -//import "crypto/rand" -import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" -import "github.com/deroproject/derohe/crypto/sha3" - -// the original try and increment method A Note on Hashing to BN Curves https://www.normalesup.org/~tibouchi/papers/bnhash-scis.pdf -// see this for a simplified version https://github.com/clearmatics/mobius/blob/7ad988b816b18e22424728329fc2b166d973a120/contracts/bn256g1.sol - -var FIELD_MODULUS, w = new(big.Int).SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47", 16) -var GROUP_MODULUS, w1 = new(big.Int).SetString("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", 16) - -// this file basically implements curve based items - -type GeneratorParams struct { - G *bn256.G1 - H *bn256.G1 - GSUM *bn256.G1 - - Gs *PointVector - Hs *PointVector -} - -// converts a big int to 32 bytes, prepending zeroes -func ConvertBigIntToByte(x *big.Int) []byte { - var dummy [128]byte - joined := append(dummy[:], x.Bytes()...) - return joined[len(joined)-32:] -} - -// the number if already reduced -func HashtoNumber(input []byte) *big.Int { - - hasher := sha3.NewLegacyKeccak256() - hasher.Write(input) - - hash := hasher.Sum(nil) - return new(big.Int).SetBytes(hash[:]) -} - -// calculate hash and reduce it by curve's order -func reducedhash(input []byte) *big.Int { - return new(big.Int).Mod(HashtoNumber(input), bn256.Order) -} - -func ReducedHash(input []byte) *big.Int { - return new(big.Int).Mod(HashtoNumber(input), bn256.Order) -} - -func makestring64(input string) string { - for len(input) != 64 { - input = "0" + input - } - return input -} - -func makestring66(input string) string { - for len(input) != 64 { - input = "0" + input - } - return input + "00" -} - -func hextobytes(input string) []byte { - ibytes, err := hex.DecodeString(input) - if err != nil { - panic(err) - } - return ibytes -} - -// p = p(u) = 36u^4 + 36u^3 + 24u^2 + 6u + 1 -var FIELD_ORDER, _ = new(big.Int).SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47", 16) - -// Number of elements in the field (often called `q`) -// n = n(u) = 36u^4 + 36u^3 + 18u^2 + 6u + 1 -var GEN_ORDER, _ = new(big.Int).SetString("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", 16) - -var CURVE_B = new(big.Int).SetUint64(3) - -// a = (p+1) / 4 -var CURVE_A, _ = new(big.Int).SetString("c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52", 16) - -func HashToPointNew(seed *big.Int) *bn256.G1 { - y_squared := new(big.Int) - one := new(big.Int).SetUint64(1) - - x := new(big.Int).Set(seed) - x.Mod(x, GEN_ORDER) - for { - beta, y := findYforX(x) - - if y != nil { - - // fmt.Printf("beta %s y %s\n", beta.String(),y.String()) - - // y^2 == beta - y_squared.Mul(y, y) - y_squared.Mod(y_squared, FIELD_ORDER) - - if beta.Cmp(y_squared) == 0 { - - // fmt.Printf("liesoncurve test %+v\n", isOnCurve(x,y)) - // fmt.Printf("x %s\n",x.Text(16)) - // fmt.Printf("y %s\n",y.Text(16)) - - xstring := x.Text(16) - ystring := y.Text(16) - - var point bn256.G1 - xbytes, err := hex.DecodeString(makestring64(xstring)) - if err != nil { - panic(err) - } - ybytes, err := hex.DecodeString(makestring64(ystring)) - if err != nil { - panic(err) - } - - if _, err := point.Unmarshal(append(xbytes, ybytes...)); err == nil { - return &point - } else { - - panic(fmt.Sprintf("not found err %s\n", err)) - } - } - } - - x.Add(x, one) - x.Mod(x, FIELD_ORDER) - } - -} - -/* - * Given X, find Y - * - * where y = sqrt(x^3 + b) - * - * Returns: (x^3 + b), y -**/ -func findYforX(x *big.Int) (*big.Int, *big.Int) { - // beta = (x^3 + b) % p - xcube := new(big.Int).Exp(x, CURVE_B, FIELD_ORDER) - xcube.Add(xcube, CURVE_B) - beta := new(big.Int).Mod(xcube, FIELD_ORDER) - //beta := addmod(mulmod(mulmod(x, x, FIELD_ORDER), x, FIELD_ORDER), CURVE_B, FIELD_ORDER); - - // y^2 = x^3 + b - // this acts like: y = sqrt(beta) - - //ymod := new(big.Int).ModSqrt(beta,FIELD_ORDER) // this can return nil in some cases - y := new(big.Int).Exp(beta, CURVE_A, FIELD_ORDER) - return beta, y -} - -/* - * Verify if the X and Y coordinates represent a valid Point on the Curve - * - * Where the G1 curve is: x^2 = x^3 + b -**/ -func isOnCurve(x, y *big.Int) bool { - //p_squared := new(big.Int).Exp(x, new(big.Int).SetUint64(2), FIELD_ORDER); - p_cubed := new(big.Int).Exp(x, new(big.Int).SetUint64(3), FIELD_ORDER) - - p_cubed.Add(p_cubed, CURVE_B) - p_cubed.Mod(p_cubed, FIELD_ORDER) - - // return addmod(p_cubed, CURVE_B, FIELD_ORDER) == mulmod(p.Y, p.Y, FIELD_ORDER); - return p_cubed.Cmp(new(big.Int).Exp(y, new(big.Int).SetUint64(2), FIELD_ORDER)) == 0 -} - -// this should be merged , simplified just as simple as 25519 -func HashToPoint(seed *big.Int) *bn256.G1 { - /* - var x, _ = new(big.Int).SetString("0d36fdf1852f1563df9c904374055bb2a4d351571b853971764b9561ae203a9e",16) - var y, _ = new(big.Int).SetString("06efda2e606d7bafec34b82914953fa253d21ca3ced18db99c410e9057dccd50",16) - - - - fmt.Printf("hardcode point on curve %+v\n", isOnCurve(x,y)) - panic("done") - */ - return HashToPointNew(seed) - - seed_reduced := new(big.Int) - seed_reduced.Mod(seed, FIELD_MODULUS) - - counter := 0 - - p_1_4 := new(big.Int).Add(FIELD_MODULUS, new(big.Int).SetInt64(1)) - p_1_4 = p_1_4.Div(p_1_4, new(big.Int).SetInt64(4)) - - for { - tmp := new(big.Int) - y, y_squared, y_resquare := new(big.Int), new(big.Int), new(big.Int) // basically y_sqaured = seed ^3 + 3 mod group order - tmp.Exp(seed_reduced, new(big.Int).SetInt64(3), FIELD_MODULUS) - y_squared.Add(tmp, new(big.Int).SetInt64(3)) - y_squared.Mod(y_squared, FIELD_MODULUS) - - y = y.Exp(y_squared, p_1_4, FIELD_MODULUS) - - y_resquare = y_resquare.Exp(y, new(big.Int).SetInt64(2), FIELD_MODULUS) - - if y_resquare.Cmp(y_squared) == 0 { // seed becomes x and y iis usy - xstring := seed_reduced.Text(16) - ystring := y.Text(16) - - var point bn256.G1 - xbytes, err := hex.DecodeString(makestring64(xstring)) - if err != nil { - panic(err) - } - ybytes, err := hex.DecodeString(makestring64(ystring)) - if err != nil { - panic(err) - } - - if _, err = point.Unmarshal(append(xbytes, ybytes...)); err == nil { - return &point - } else { - // continue finding - counter++ - - if counter%10000 == 0 { - fmt.Printf("tried %d times\n", counter) - } - - } - - } - seed_reduced.Add(seed_reduced, new(big.Int).SetInt64(1)) - seed_reduced.Mod(seed_reduced, FIELD_MODULUS) - } - - return nil -} diff --git a/crypto/keccak.go b/crypto/keccak.go deleted file mode 100644 index c65a972..0000000 --- a/crypto/keccak.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "golang.org/x/crypto/sha3" -import "github.com/deroproject/derohe/crypto/sha3" - -// quick keccak wrapper -func Keccak256(data ...[]byte) (result Hash) { - h := sha3.NewLegacyKeccak256() - for _, b := range data { - h.Write(b) - } - r := h.Sum(nil) - copy(result[:], r) - return -} - -func Keccak512(data ...[]byte) (result Hash) { - h := sha3.NewLegacyKeccak512() - for _, b := range data { - h.Write(b) - } - r := h.Sum(nil) - copy(result[:], r) - return -} diff --git a/crypto/keccak_test.go b/crypto/keccak_test.go deleted file mode 100644 index bc614e8..0000000 --- a/crypto/keccak_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017-2018 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "testing" -import "encoding/hex" - -func TestKeccak256(t *testing.T) { - tests := []struct { - name string - messageHex string - wantHex string - }{ - { - name: "from monero 1", - messageHex: "c8fedd380dbae40ffb52", - wantHex: "8e41962058b7422e7404253121489a3e63d186ed115086919a75105661483ba9", - }, - { - name: "from monero 2", - messageHex: "5020c4d530b6ec6cb4d9", - wantHex: "8a597f11961935e32e0adeab2ce48b3df2d907c9b26619dad22f42ff65ab7593", - }, - { - name: "hello", - messageHex: "68656c6c6f", - wantHex: "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8", - }, - { - name: "from monero cryptotest.pl", - messageHex: "0f3fe9c20b24a11bf4d6d1acd335c6a80543f1f0380590d7323caf1390c78e88", - wantHex: "73b7a236f2a97c4e1805f7a319f1283e3276598567757186c526caf9a49e0a92", - }, - } - for _, test := range tests { - message, _ := hex.DecodeString(test.messageHex) - got := Keccak256(message) - want := HexToHash(test.wantHex) - if want != got { - t.Errorf("want %x, got %x", want, got) - } - } -} diff --git a/crypto/key_old.go b/crypto/key_old.go deleted file mode 100644 index d4ab96c..0000000 --- a/crypto/key_old.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "encoding/hex" - -const KeyLength = 32 - -// Key can be a Scalar or a Point -type Key [KeyLength]byte - -func (k Key) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("%x", k[:])), nil -} - -func (k *Key) UnmarshalText(data []byte) (err error) { - byteSlice, _ := hex.DecodeString(string(data)) - if len(byteSlice) != 32 { - return fmt.Errorf("Incorrect key size") - } - copy(k[:], byteSlice) - return -} - -func (k Key) String() string { - return fmt.Sprintf("%x", k[:]) -} - -func (p *Key) FromBytes(b [KeyLength]byte) { - *p = b -} - -func (p *Key) ToBytes() (result [KeyLength]byte) { - result = [KeyLength]byte(*p) - return -} - -// convert a hex string to a key -func HexToKey(h string) (result Key) { - byteSlice, _ := hex.DecodeString(h) - if len(byteSlice) != 32 { - panic("Incorrect key size") - } - copy(result[:], byteSlice) - return -} - -func HexToHash(h string) (result Hash) { - byteSlice, _ := hex.DecodeString(h) - if len(byteSlice) != 32 { - panic("Incorrect key size") - } - copy(result[:], byteSlice) - return -} diff --git a/crypto/paymentid.go b/crypto/paymentid.go deleted file mode 100644 index 519e3e5..0000000 --- a/crypto/paymentid.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "github.com/deroproject/derohe/crypto/bn256" - -// BUG BUG BUG this needs to be updated and add more context -// this function is used to encrypt/decrypt payment id -// as the operation is symmetric XOR, is the same in both direction -// -func EncryptDecryptPaymentID(blinder *bn256.G1, input []byte) (output []byte) { - - // input must be exactly 8 bytes long - if len(input) != 8 { - panic("Encrypted payment ID must be exactly 8 bytes long") - } - output = make([]byte, 8, 8) - - blinder_compressed := blinder.EncodeCompressed() - if len(blinder_compressed) != 33 { - panic("point compression needs to be fixed") - } - // Todo we should take the hash - - blinder_compressed = blinder_compressed[25:] // we will use last 8 bytes - - for l := range input { - output[l] = input[l] ^ blinder_compressed[l] // xor the bytes with the hash - } - - /* - var tmp_buf [33]byte - copy(tmp_buf[:], derivation[:]) // copy derivation key to buffer - tmp_buf[32] = ENCRYPTED_PAYMENT_ID_TAIL - - // take hash - hash := crypto.Keccak256(tmp_buf[:]) // take hash of entire 33 bytes, 32 bytes derivation key, 1 byte tail - - output = make([]byte, 8, 8) - for i := range input { - output[i] = input[i] ^ hash[i] // xor the bytes with the hash - } - */ - return -} diff --git a/crypto/polynomial.go b/crypto/polynomial.go deleted file mode 100644 index f81e7e4..0000000 --- a/crypto/polynomial.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math/big" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -type Polynomial struct { - coefficients []*big.Int -} - -func NewPolynomial(input []*big.Int) *Polynomial { - if input == nil { - return &Polynomial{coefficients: []*big.Int{new(big.Int).SetInt64(1)}} - } - return &Polynomial{coefficients: input} -} - -func (p *Polynomial) Length() int { - return len(p.coefficients) -} - -func (p *Polynomial) Mul(m *Polynomial) *Polynomial { - var product []*big.Int - for i := range p.coefficients { - product = append(product, new(big.Int).Mod(new(big.Int).Mul(p.coefficients[i], m.coefficients[0]), bn256.Order)) - } - product = append(product, new(big.Int)) // add 0 element - - if m.coefficients[1].IsInt64() && m.coefficients[1].Int64() == 1 { - for i := range product { - if i > 0 { - tmp := new(big.Int).Add(product[i], p.coefficients[i-1]) - - product[i] = new(big.Int).Mod(tmp, bn256.Order) - - } else { // do nothing - - } - } - } - return NewPolynomial(product) -} - -type dummy struct { - list [][]*big.Int -} - -func RecursivePolynomials(list [][]*big.Int, accum *Polynomial, a, b []*big.Int) (rlist [][]*big.Int) { - var d dummy - d.recursivePolynomialsinternal(accum, a, b) - - return d.list -} - -func (d *dummy) recursivePolynomialsinternal(accum *Polynomial, a, b []*big.Int) { - if len(a) == 0 { - d.list = append(d.list, accum.coefficients) - return - } - - atop := a[len(a)-1] - btop := b[len(b)-1] - - left := NewPolynomial([]*big.Int{new(big.Int).Mod(new(big.Int).Neg(atop), bn256.Order), new(big.Int).Mod(new(big.Int).Sub(new(big.Int).SetInt64(1), btop), bn256.Order)}) - right := NewPolynomial([]*big.Int{atop, btop}) - - d.recursivePolynomialsinternal(accum.Mul(left), a[:len(a)-1], b[:len(b)-1]) - d.recursivePolynomialsinternal(accum.Mul(right), a[:len(a)-1], b[:len(b)-1]) -} diff --git a/crypto/proof_generate.go b/crypto/proof_generate.go deleted file mode 100644 index 0b0d5a7..0000000 --- a/crypto/proof_generate.go +++ /dev/null @@ -1,1206 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "fmt" -import "math" -import "math/big" -import "bytes" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -//import "github.com/kubernetes/klog" - -type Proof struct { - BA *bn256.G1 - BS *bn256.G1 - A *bn256.G1 - B *bn256.G1 - - CLnG, CRnG, C_0G, DG, y_0G, gG, C_XG, y_XG []*bn256.G1 - - u *bn256.G1 - - f *FieldVector - - z_A *big.Int - - T_1 *bn256.G1 - T_2 *bn256.G1 - - that *big.Int - mu *big.Int - - c *big.Int - s_sk, s_r, s_b, s_tau *big.Int - - ip *InnerProduct -} - -type IPStatement struct { - PrimeBase *GeneratorParams - P *bn256.G1 -} - -type IPWitness struct { - L *FieldVector - R *FieldVector -} - -// this is based on roothash and user's secret key and thus is the basis of protection from a number of double spending attacks -func (p *Proof) Nonce() Hash { - return Keccak256(p.u.EncodeCompressed()) -} - -func (p *Proof) Serialize(w *bytes.Buffer) { - if p == nil { - return - } - w.Write(p.BA.EncodeCompressed()) - w.Write(p.BS.EncodeCompressed()) - w.Write(p.A.EncodeCompressed()) - w.Write(p.B.EncodeCompressed()) - - //w.WriteByte(byte(len(p.CLnG))) // we can skip this byte also, why not skip it - - // fmt.Printf("CLnG byte %d\n",len(p.CLnG)) - for i := 0; i < len(p.CLnG); i++ { - w.Write(p.CLnG[i].EncodeCompressed()) - w.Write(p.CRnG[i].EncodeCompressed()) - w.Write(p.C_0G[i].EncodeCompressed()) - w.Write(p.DG[i].EncodeCompressed()) - w.Write(p.y_0G[i].EncodeCompressed()) - w.Write(p.gG[i].EncodeCompressed()) - w.Write(p.C_XG[i].EncodeCompressed()) - w.Write(p.y_XG[i].EncodeCompressed()) - } - - w.Write(p.u.EncodeCompressed()) - - if len(p.CLnG) != len(p.f.vector) { - /// panic(fmt.Sprintf("different size %d %d", len(p.CLnG), len(p.f.vector))) - } - - /*if len(p.f.vector) != 2 { - panic(fmt.Sprintf("f could not be serialized length %d", len(p.CLnG), len(p.f.vector))) - } - */ - - // fmt.Printf("writing %d fvector points\n", len(p.f.vector)); - for i := 0; i < len(p.f.vector); i++ { - w.Write(ConvertBigIntToByte(p.f.vector[i])) - } - - w.Write(ConvertBigIntToByte(p.z_A)) - - w.Write(p.T_1.EncodeCompressed()) - w.Write(p.T_2.EncodeCompressed()) - - w.Write(ConvertBigIntToByte(p.that)) - w.Write(ConvertBigIntToByte(p.mu)) - - w.Write(ConvertBigIntToByte(p.c)) - w.Write(ConvertBigIntToByte(p.s_sk)) - w.Write(ConvertBigIntToByte(p.s_r)) - w.Write(ConvertBigIntToByte(p.s_b)) - w.Write(ConvertBigIntToByte(p.s_tau)) - - p.ip.Serialize(w) - -} - -func (proof *Proof) Deserialize(r *bytes.Reader, length int) error { - - var buf [32]byte - var bufp [33]byte - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.BA = &p - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.BS = &p - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.A = &p - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.B = &p - } else { - return err - } - - proof.CLnG = proof.CLnG[:0] - proof.CRnG = proof.CRnG[:0] - proof.C_0G = proof.C_0G[:0] - proof.DG = proof.DG[:0] - proof.y_0G = proof.y_0G[:0] - proof.gG = proof.gG[:0] - proof.C_XG = proof.C_XG[:0] - proof.y_XG = proof.y_XG[:0] - - for i := 0; i < length; i++ { - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.CLnG = append(proof.CLnG, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - //fmt.Printf("CRnG point bytes2 %x\n", bufp[:]) - if err = p.DecodeCompressed(bufp[:]); err != nil { - //fmt.Printf("CRng point bytes1 %x\n", bufp[:]) - return err - } - proof.CRnG = append(proof.CRnG, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.C_0G = append(proof.C_0G, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.DG = append(proof.DG, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.y_0G = append(proof.y_0G, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.gG = append(proof.gG, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.C_XG = append(proof.C_XG, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.y_XG = append(proof.y_XG, &p) - } else { - return err - } - - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.u = &p - } else { - return err - } - - proof.f = &FieldVector{} - - //fmt.Printf("flen %d\n", flen ) - for j := 0; j < length*2; j++ { - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.f.vector = append(proof.f.vector, new(big.Int).SetBytes(buf[:])) - } else { - return err - } - - } - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.z_A = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.T_1 = &p - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - proof.T_2 = &p - } else { - return err - } - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.that = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.mu = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.c = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.s_sk = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.s_r = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.s_b = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - if n, err := r.Read(buf[:]); n == 32 && err == nil { - proof.s_tau = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - proof.ip = &InnerProduct{} - - return proof.ip.Deserialize(r) - -} - -/* -// statement hash -func (s *Statement) Hash() *big.Int { - var input []byte - for i := range s.CLn { - input = append(input, s.CLn[i].Marshal()...) - } - for i := range s.CRn { - input = append(input, s.CRn[i].Marshal()...) - } - for i := range s.C { - input = append(input, s.C[i].Marshal()...) - } - input = append(input, s.D.Marshal()...) - for i := range s.Publickeylist { - input = append(input, s.Publickeylist[i].Marshal()...) - } - input = append(input, s.Roothash[:]...) - - return reducedhash(input) -} -*/ - -func (p *Proof) Size() int { - size := 4*POINT_SIZE + (len(p.CLnG)+len(p.CRnG)+len(p.C_0G)+len(p.DG)+len(p.y_0G)+len(p.gG)+len(p.C_XG)+len(p.y_XG))*POINT_SIZE - size += POINT_SIZE - size += len(p.f.vector) * FIELDELEMENT_SIZE - size += FIELDELEMENT_SIZE - size += 2 * POINT_SIZE // T_1 ,T_2 - size += 7 * FIELDELEMENT_SIZE - size += p.ip.Size() - return size -} - -func (proof *Proof) hashmash1(v *big.Int) *big.Int { - var input []byte - input = append(input, ConvertBigIntToByte(v)...) - for i := range proof.CLnG { - input = append(input, proof.CLnG[i].Marshal()...) - } - for i := range proof.CRnG { - input = append(input, proof.CRnG[i].Marshal()...) - } - for i := range proof.C_0G { - input = append(input, proof.C_0G[i].Marshal()...) - } - for i := range proof.DG { - input = append(input, proof.DG[i].Marshal()...) - } - for i := range proof.y_0G { - input = append(input, proof.y_0G[i].Marshal()...) - } - for i := range proof.gG { - input = append(input, proof.gG[i].Marshal()...) - } - for i := range proof.C_XG { - input = append(input, proof.C_XG[i].Marshal()...) - } - for i := range proof.y_XG { - input = append(input, proof.y_XG[i].Marshal()...) - } - return reducedhash(input) -} - -// function, which takes a string as -// argument and return the reverse of string. -func reverse(s string) string { - rns := []rune(s) // convert to rune - for i, j := 0, len(rns)-1; i < j; i, j = i+1, j-1 { - - // swap the letters of the string, - // like first with last and so on. - rns[i], rns[j] = rns[j], rns[i] - } - - // return the reversed string. - return string(rns) -} - -var params = NewGeneratorParams(128) // these can be pregenerated similarly as in DERO project - -func GenerateProof(s *Statement, witness *Witness, u *bn256.G1, txid Hash) *Proof { - - var proof Proof - proof.u = u - - statementhash := reducedhash(txid[:]) - - // statement should be constructed from these, however these are being simplified - var C []*ElGamal - var Cn ElGamalVector - for i := range s.C { - C = append(C, ConstructElGamal(s.C[i], s.D)) - Cn.vector = append(Cn.vector, ConstructElGamal(s.CLn[i], s.CRn[i])) - } - - btransfer := new(big.Int).SetInt64(int64(witness.TransferAmount)) // this should be reduced - bdiff := new(big.Int).SetInt64(int64(witness.Balance)) // this should be reduced - - number := btransfer.Add(btransfer, bdiff.Lsh(bdiff, 64)) // we are placing balance and left over balance, and doing a range proof of 128 bits - - number_string := reverse("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + number.Text(2)) - number_string_left_128bits := string(number_string[0:128]) - - var aL, aR FieldVector // convert the amount to make sure it cannot be negative - - //klog.V(2).Infof("reverse %s\n", number_string_left_128bits) - for _, b := range []byte(number_string_left_128bits) { - if b == '1' { - aL.vector = append(aL.vector, new(big.Int).SetInt64(1)) - aR.vector = append(aR.vector, new(big.Int).SetInt64(0)) - } else { - aL.vector = append(aL.vector, new(big.Int).SetInt64(0)) - aR.vector = append(aR.vector, new(big.Int).Mod(new(big.Int).SetInt64(-1), bn256.Order)) - } - } - - //klog.V(2).Infof("aRa %+v\n", aRa) - - proof_BA_internal := NewPedersenVectorCommitment().Commit(&aL, &aR) - proof.BA = proof_BA_internal.Result - - sL := NewFieldVectorRandomFilled(len(aL.vector)) - sR := NewFieldVectorRandomFilled(len(aL.vector)) - proof_BS_internal := NewPedersenVectorCommitment().Commit(sL, sR) - proof.BS = proof_BS_internal.Result - - //klog.V(2).Infof("Proof BA %s\n", proof.BA.String()) - //klog.V(2).Infof("Proof BS %s\n", proof.BS.String()) - - if len(s.Publickeylist) >= 1 && len(s.Publickeylist)&(len(s.Publickeylist)-1) != 0 { - fmt.Printf("len of Publickeylist %d\n", len(s.Publickeylist)) - panic("we need power of 2") - } - - N := len(s.Publickeylist) - m := int(math.Log2(float64(N))) - - if math.Pow(2, float64(m)) != float64(N) { - panic("log failed") - } - - var aa, ba, bspecial []*big.Int - for i := 0; i < 2*m; i++ { - aa = append(aa, RandomScalarFixed()) - } - - witness_index := reverse(fmt.Sprintf("%0"+fmt.Sprintf("%db", m)+"%0"+fmt.Sprintf("%db", m), witness.Index[1], witness.Index[0])) - - for _, b := range []byte(witness_index) { - if b == '1' { - ba = append(ba, new(big.Int).SetUint64(1)) - bspecial = append(bspecial, new(big.Int).Mod(new(big.Int).SetInt64(-1), bn256.Order)) - } else { - ba = append(ba, new(big.Int).SetUint64(0)) - bspecial = append(bspecial, new(big.Int).Mod(new(big.Int).SetInt64(1), bn256.Order)) - } - } - - a := NewFieldVector(aa) - b := NewFieldVector(ba) - - // klog.V(1).Infof("witness_index of sender/receiver %s\n", witness_index) - - c := a.Hadamard(NewFieldVector(bspecial)) - d := a.Hadamard(a).Negate() - - // klog.V(2).Infof("d %s\n", d.vector[0].Text(16)) - - e := NewFieldVector([]*big.Int{new(big.Int).Mod(new(big.Int).Mul(a.vector[0], a.vector[m]), bn256.Order), - new(big.Int).Mod(new(big.Int).Mul(a.vector[0], a.vector[m]), bn256.Order)}) - - second := new(big.Int).Set(a.vector[b.vector[m].Uint64()*uint64(m)]) - second.Neg(second) - - f := NewFieldVector([]*big.Int{a.vector[b.vector[0].Uint64()*uint64(m)], new(big.Int).Mod(second, bn256.Order)}) - - // for i := range f.vector { - // klog.V(2).Infof("f %d %s\n", i, f.vector[i].Text(16)) - // } - - proof_A_internal := NewPedersenVectorCommitment().Commit(a, d.Concat(e)) - proof.A = proof_A_internal.Result - proof_B_internal := NewPedersenVectorCommitment().Commit(b, c.Concat(f)) - proof.B = proof_B_internal.Result - - // klog.V(2).Infof("Proof A %s\n", proof.A.String()) - // klog.V(2).Infof("Proof B %s\n", proof.B.String()) - - var v *big.Int - - { // hash mash - var input []byte - input = append(input, ConvertBigIntToByte(statementhash)...) - input = append(input, proof.BA.Marshal()...) - input = append(input, proof.BS.Marshal()...) - input = append(input, proof.A.Marshal()...) - input = append(input, proof.B.Marshal()...) - v = reducedhash(input) - } - - var P, Q, Pi, Qi [][]*big.Int - Pi = RecursivePolynomials(Pi, NewPolynomial(nil), a.SliceRaw(0, m), b.SliceRaw(0, m)) - Qi = RecursivePolynomials(Qi, NewPolynomial(nil), a.SliceRaw(m, 2*m), b.SliceRaw(m, 2*m)) - - // transpose the matrices - for i := 0; i < m; i++ { - P = append(P, []*big.Int{}) - Q = append(Q, []*big.Int{}) - for j := range Pi { - P[i] = append(P[i], Pi[j][i]) - Q[i] = append(Q[i], Qi[j][i]) - } - } - - // for i := range P { - // for j := range P[i] { - // klog.V(2).Infof("P%d,%d %s\n", i, j, P[i][j].Text(16)) - // } - // } - - //phi := NewFieldVectorRandomFilled(m) - //chi := NewFieldVectorRandomFilled(m) - //psi := NewFieldVectorRandomFilled(m) - - var phi, chi, psi ElGamalVector - for i := 0; i < m; i++ { - phi.vector = append(phi.vector, CommitElGamal(s.Publickeylist[witness.Index[0]], new(big.Int).SetUint64(0))) - chi.vector = append(chi.vector, CommitElGamal(s.Publickeylist[witness.Index[0]], new(big.Int).SetUint64(0))) - psi.vector = append(psi.vector, CommitElGamal(s.Publickeylist[witness.Index[0]], new(big.Int).SetUint64(0))) - } - - var CnG, C_0G, y_0G ElGamalVector - for i := 0; i < m; i++ { - - CnG.vector = append(CnG.vector, Cn.MultiExponentiate(NewFieldVector(P[i])).Add(phi.vector[i])) - - { - var pvector PointVector - for j := range C { - pvector.vector = append(pvector.vector, C[j].Left) - } - left := pvector.MultiExponentiate(NewFieldVector(P[i])) //.Add(chi.vector[i].Left) - left = new(bn256.G1).Add(new(bn256.G1).Set(left), chi.vector[i].Left) - C_0G.vector = append(C_0G.vector, ConstructElGamal(left, chi.vector[i].Right)) - } - - { - - left := NewPointVector(s.Publickeylist).MultiExponentiate(NewFieldVector(P[i])) - left = new(bn256.G1).Add(new(bn256.G1).Set(left), psi.vector[i].Left) - y_0G.vector = append(y_0G.vector, ConstructElGamal(left, psi.vector[i].Right)) - } - - /* - { // y_0G - var rightp, result bn256.G1 - leftp := NewPointVector(s.Publickeylist).Commit(P[i]) - rightp.ScalarMult(s.Publickeylist[witness.Index[0]], psi.vector[i]) - result.Add(leftp, &rightp) - proof.y_0G = append(proof.y_0G, &result) - //klog.V(2).Infof("y_0G %d %s\n",i, result.String()) - } - - { // gG - var result bn256.G1 - result.ScalarMult(params.G, psi.vector[i]) - proof.gG = append(proof.gG, &result) - //klog.V(2).Infof("gG %d %s\n",i, result.String()) - } - */ - - /* - { // C_XG - var result bn256.G1 - result.ScalarMult(s.D, omega.vector[i]) - proof.C_XG = append(proof.C_XG, &result) - //klog.V(2).Infof("C_XG %d %s\n",i, result.String()) - } - - { // y_XG - var result bn256.G1 - result.ScalarMult(params.G, omega.vector[i]) - proof.y_XG = append(proof.y_XG, &result) - klog.V(2).Infof("y_XG %d %s\n", i, result.String()) - } - */ - - } - - /* - for i := range proof.CLnG { - klog.V(2).Infof("CLnG %d %s\n", i, proof.CLnG[i].String()) - } - for i := range proof.CRnG { - klog.V(2).Infof("CRnG %d %s\n", i, proof.CRnG[i].String()) - } - for i := range proof.C_0G { - klog.V(2).Infof("C_0G %d %s\n", i, proof.C_0G[i].String()) - } - for i := range proof.DG { - klog.V(2).Infof("DG %d %s\n", i, proof.DG[i].String()) - } - for i := range proof.y_0G { - klog.V(2).Infof("y_0G %d %s\n", i, proof.y_0G[i].String()) - } - for i := range proof.gG { - klog.V(2).Infof("gG %d %s\n", i, proof.gG[i].String()) - } - for i := range proof.C_XG { - klog.V(2).Infof("C_XG %d %s\n", i, proof.C_XG[i].String()) - } - for i := range proof.y_XG { - klog.V(2).Infof("y_XG %d %s\n", i, proof.y_XG[i].String()) - } - */ - var C_XG []*ElGamal - for i := 0; i < m; i++ { - C_XG = append(C_XG, CommitElGamal(C[0].Right, new(big.Int).SetUint64(0))) - } - - vPow := new(big.Int).SetInt64(1) // doesn't need reduction, since it' alredy reduced - - for i := 0; i < N; i++ { - - var poly [][]*big.Int - if i%2 == 0 { - poly = P - } else { - poly = Q - } - - // klog.V(2).Infof("\n\n") - // for i := range proof.C_XG { - // klog.V(2).Infof("C_XG before %d %s\n", i, proof.C_XG[i].String()) - // } - - // klog.V(2).Infof("loop %d pos in poly sender %d receiver %d\n", i, (witness.Index[0]+N-(i-i%2))%N, (witness.Index[1]+N-(i-i%2))%N) - - for j := range C_XG { - - amount := new(big.Int).SetUint64(uint64(witness.TransferAmount)) - amount_neg := new(big.Int).Neg(amount) - amount_fees := new(big.Int).SetUint64(s.Fees) - left := new(big.Int).Sub(amount_neg, amount_fees) - left = new(big.Int).Mod(new(big.Int).Mul(new(big.Int).Set(left), poly[j][(witness.Index[0]+N-(i-i%2))%N]), bn256.Order) - - right := new(big.Int).Mod(new(big.Int).Mul(new(big.Int).Set(amount), poly[j][(witness.Index[1]+N-(i-i%2))%N]), bn256.Order) - - joined := new(big.Int).Mod(new(big.Int).Add(left, right), bn256.Order) - - mul := new(big.Int).Mod(new(big.Int).Mul(vPow, joined), bn256.Order) - - C_XG[j] = C_XG[j].Plus(mul) - } - - if i != 0 { - vPow.Mul(vPow, v) - vPow.Mod(vPow, bn256.Order) - } - - //klog.V(2).Infof("vPow %d %s\n", i, vPow.Text(16))) - - } - - for i := range C_XG { - proof.C_XG = append(proof.C_XG, C_XG[i].Left) - proof.y_XG = append(proof.y_XG, C_XG[i].Right) - - proof.CLnG = append(proof.CLnG, CnG.vector[i].Left) - proof.CRnG = append(proof.CRnG, CnG.vector[i].Right) - - proof.C_0G = append(proof.C_0G, C_0G.vector[i].Left) - proof.DG = append(proof.DG, C_0G.vector[i].Right) - - proof.y_0G = append(proof.y_0G, y_0G.vector[i].Left) - proof.gG = append(proof.gG, y_0G.vector[i].Right) - } - - //klog.V(2).Infof("\n\n") - // for i := range proof.C_XG { - // klog.V(2).Infof("C_XG after %d %s\n", i, proof.C_XG[i].String()) - // } - - // calculate w hashmash - - w := proof.hashmash1(v) - - { - var input []byte - - input = append(input, ConvertBigIntToByte(v)...) - for i := range proof.CLnG { - input = append(input, proof.CLnG[i].Marshal()...) - } - for i := range proof.CRnG { - input = append(input, proof.CRnG[i].Marshal()...) - } - - for i := range proof.C_0G { - input = append(input, proof.C_0G[i].Marshal()...) - } - for i := range proof.DG { - input = append(input, proof.DG[i].Marshal()...) - } - for i := range proof.y_0G { - input = append(input, proof.y_0G[i].Marshal()...) - } - for i := range proof.gG { - input = append(input, proof.gG[i].Marshal()...) - } - for i := range C_XG { - input = append(input, C_XG[i].Left.Marshal()...) - } - for i := range proof.y_XG { - input = append(input, C_XG[i].Right.Marshal()...) - } - //fmt.Printf("whash %s %s\n", reducedhash(input).Text(16), w.Text(16)) - - } - - proof.f = b.Times(w).Add(a) - - // for i := range proof.f.vector { - // klog.V(2).Infof("proof.f %d %s\n", i, proof.f.vector[i].Text(16)) - // } - - ttttt := new(big.Int).Mod(new(big.Int).Mul(proof_B_internal.Randomness, w), bn256.Order) - proof.z_A = new(big.Int).Mod(new(big.Int).Add(ttttt, proof_A_internal.Randomness), bn256.Order) - - // klog.V(2).Infof("proofz_A %s\n", proof.z_A.Text(16)) - - y := reducedhash(ConvertBigIntToByte(w)) - - // klog.V(2).Infof("yyyyyyyyyy %s\n", y.Text(16)) - - ys_raw := []*big.Int{new(big.Int).SetUint64(1)} - for i := 1; i < 128; i++ { - var tt big.Int - tt.Mul(ys_raw[len(ys_raw)-1], y) - tt.Mod(&tt, bn256.Order) - ys_raw = append(ys_raw, &tt) - } - ys := NewFieldVector(ys_raw) - - z := reducedhash(ConvertBigIntToByte(y)) - // klog.V(2).Infof("zzzzzzzzzz %s \n", z.Text(16)) - - zs := []*big.Int{new(big.Int).Exp(z, new(big.Int).SetUint64(2), bn256.Order), new(big.Int).Exp(z, new(big.Int).SetUint64(3), bn256.Order)} - // for i := range zs { - // klog.V(2).Infof("zs %d %s\n", i, zs[i].Text(16)) - // } - - twos := []*big.Int{new(big.Int).SetUint64(1)} - for i := 1; i < 64; i++ { - var tt big.Int - tt.Mul(twos[len(twos)-1], new(big.Int).SetUint64(2)) - tt.Mod(&tt, bn256.Order) - twos = append(twos, &tt) - } - - twoTimesZs := []*big.Int{} - for i := 0; i < 2; i++ { - for j := 0; j < 64; j++ { - var tt big.Int - tt.Mul(zs[i], twos[j]) - tt.Mod(&tt, bn256.Order) - twoTimesZs = append(twoTimesZs, &tt) - - // klog.V(2).Infof("twoTimesZssss ============= %d %s\n", i*32+j, twoTimesZs[i*32+j].Text(16)) - - } - } - - tmp := aL.AddConstant(new(big.Int).Mod(new(big.Int).Neg(z), bn256.Order)) - lPoly := NewFieldVectorPolynomial(tmp, sL) - //for i := range lPoly.coefficients { - // for j := range lPoly.coefficients[i].vector { - // klog.V(2).Infof("lPoly %d,%d %s\n", i, j, lPoly.coefficients[i].vector[j].Text(16)) - // } - //} - - rPoly := NewFieldVectorPolynomial(ys.Hadamard(aR.AddConstant(z)).Add(NewFieldVector(twoTimesZs)), sR.Hadamard(ys)) - //for i := range rPoly.coefficients { - // for j := range rPoly.coefficients[i].vector { - // klog.V(2).Infof("rPoly %d,%d %s\n", i, j, rPoly.coefficients[i].vector[j].Text(16)) - // } - //} - - tPolyCoefficients := lPoly.InnerProduct(rPoly) // just an array of BN Reds... should be length 3 - //for j := range tPolyCoefficients { - // klog.V(2).Infof("tPolyCoefficients %d,%d %s\n", 0, j, tPolyCoefficients[j].Text(16)) - //} - - proof_T1 := NewPedersenCommitmentNew().Commit(tPolyCoefficients[1]) - proof_T2 := NewPedersenCommitmentNew().Commit(tPolyCoefficients[2]) - proof.T_1 = proof_T1.Result - proof.T_2 = proof_T2.Result - - //polyCommitment := NewPolyCommitment(params, tPolyCoefficients) - /*proof.tCommits = NewPointVector(polyCommitment.GetCommitments()) - - for j := range proof.tCommits.vector { - klog.V(2).Infof("tCommits %d %s\n", j, proof.tCommits.vector[j].String()) - } - */ - - x := new(big.Int) - - { - var input []byte - input = append(input, ConvertBigIntToByte(z)...) // tie intermediates/commit - //for j := range proof.tCommits.vector { - // input = append(input, proof.tCommits.vector[j].Marshal()...) - //} - input = append(input, proof_T1.Result.Marshal()...) - input = append(input, proof_T2.Result.Marshal()...) - x = reducedhash(input) - } - - //klog.V(2).Infof("x %s\n", x.Text(16)) - - //evalCommit := polyCommitment.Evaluate(x) - - //klog.V(2).Infof("evalCommit.X %s\n", j, evalCommit.X.Text(16)) - //klog.V(2).Infof("evalCommit.R %s\n", j, evalCommit.R.Text(16)) - - //proof.that = evalCommit.X - - xsquare := new(big.Int).Mod(new(big.Int).Mul(x, x), bn256.Order) - - proof.that = tPolyCoefficients[0] - proof.that = new(big.Int).Mod(new(big.Int).Add(proof.that, new(big.Int).Mod(new(big.Int).Mul(tPolyCoefficients[1], x), bn256.Order)), bn256.Order) - proof.that = new(big.Int).Mod(new(big.Int).Add(proof.that, new(big.Int).Mod(new(big.Int).Mul(tPolyCoefficients[2], xsquare), bn256.Order)), bn256.Order) - - /* - accumulator := new(big.Int).Set(x) - for i := 1; i < 3; i++ { - tmp := new(big.Int).Set(accumulator) - proof.that = proof.that.Add(new(bn256.G1).Set(proof.that), tPolyCoefficients[i].Times(accumulator)) - accumulator.Mod(new(big.Int).Mul(tmp, x), bn256.Order) - } - */ - - //klog.V(2).Infof("evalCommit.that %s\n", proof.that.Text(16)) - - //tauX := evalCommit.R - tauX_left := new(big.Int).Mod(new(big.Int).Mul(proof_T1.Randomness, x), bn256.Order) - tauX_right := new(big.Int).Mod(new(big.Int).Mul(proof_T2.Randomness, xsquare), bn256.Order) - tauX := new(big.Int).Mod(new(big.Int).Add(tauX_left, tauX_right), bn256.Order) - - proof.mu = new(big.Int).Mod(new(big.Int).Mul(proof_BS_internal.Randomness, x), bn256.Order) - proof.mu.Add(proof.mu, proof_BA_internal.Randomness) - proof.mu.Mod(proof.mu, bn256.Order) - - //klog.V(2).Infof("proof.mu %s\n", proof.mu.Text(16)) - - var CrnR, y_0R, y_XR bn256.G1 - // var gR bn256.G1 - CrnR.ScalarMult(params.G, new(big.Int)) - y_0R.ScalarMult(params.G, new(big.Int)) - y_XR.ScalarMult(params.G, new(big.Int)) - //DR.ScalarMult(params.G, new(big.Int)) - //gR.ScalarMult(params.G, new(big.Int)) - - CnR := ConstructElGamal(nil, ElGamal_ZERO) // only right side is needer - chi_bigint := new(big.Int).SetUint64(0) - psi_bigint := new(big.Int).SetUint64(0) - C_XR := ConstructElGamal(nil, ElGamal_ZERO) // only right side is needer - - var p_, q_ []*big.Int - for i := 0; i < N; i++ { - p_ = append(p_, new(big.Int)) - q_ = append(q_, new(big.Int)) - } - p := NewFieldVector(p_) - q := NewFieldVector(q_) - - wPow := new(big.Int).SetUint64(1) // already reduced - - for i := 0; i < m; i++ { - - { - CnR = CnR.Add(phi.vector[i].Neg().Mul(wPow)) - } - - { - mm := new(big.Int).Mod(new(big.Int).Mul(chi.vector[i].Randomness, wPow), bn256.Order) - chi_bigint = new(big.Int).Mod(new(big.Int).Add(chi_bigint, mm), bn256.Order) - } - - { - mm := new(big.Int).Mod(new(big.Int).Mul(psi.vector[i].Randomness, wPow), bn256.Order) - psi_bigint = new(big.Int).Mod(new(big.Int).Add(psi_bigint, mm), bn256.Order) - } - - /* { - tmp := new(bn256.G1) - mm := new(big.Int).Mod(new(big.Int).Neg(chi.vector[i]), bn256.Order) - mm = mm.Mod(new(big.Int).Mul(mm, wPow), bn256.Order) - tmp.ScalarMult(params.G, mm) - DR.Add(new(bn256.G1).Set(&DR), tmp) - } - - { - tmp := new(bn256.G1) - mm := new(big.Int).Mod(new(big.Int).Neg(psi.vector[i]), bn256.Order) - mm = mm.Mod(new(big.Int).Mul(mm, wPow), bn256.Order) - tmp.ScalarMult(s.Publickeylist[witness.Index[0]], mm) - y_0R.Add(new(bn256.G1).Set(&y_0R), tmp) - } - */ - /* - { - tmp := new(bn256.G1) - mm := new(big.Int).Mod(new(big.Int).Neg(psi.vector[i]), bn256.Order) - mm = mm.Mod(new(big.Int).Mul(mm, wPow), bn256.Order) - tmp.ScalarMult(params.G, mm) - gR.Add(new(bn256.G1).Set(&gR), tmp) - } - - { - tmp := new(bn256.G1) - tmp.ScalarMult(proof.y_XG[i], new(big.Int).Neg(wPow)) - y_XR.Add(new(bn256.G1).Set(&y_XR), tmp) - } - */ - - { - C_XR = C_XR.Add(C_XG[i].Neg().Mul(wPow)) - } - - //fmt.Printf("y_XG[%d] %s\n",i, proof.y_XG[i].String()) - //fmt.Printf("C_XG[%d] %s\n",i, C_XG[i].Right.String()) - - //fmt.Printf("G %s\n",G.String()) - //fmt.Printf("elgamalG %s\n",C_XG[0].G.String()) - - p = p.Add(NewFieldVector(P[i]).Times(wPow)) - q = q.Add(NewFieldVector(Q[i]).Times(wPow)) - wPow = new(big.Int).Mod(new(big.Int).Mul(wPow, w), bn256.Order) - - // klog.V(2).Infof("wPow %s\n", wPow.Text(16)) - - } - - CnR = CnR.Add(Cn.vector[witness.Index[0]].Mul(wPow)) - - //for i := range CnR{ - // proof.CLnG = append(proof.CLnG, CnR[i].Left) - // proof.CRnG = append(proof.CRnG, CnR[i].Right) - //} - - //CrnR.Add(new(bn256.G1).Set(&CrnR), new(bn256.G1).ScalarMult(s.CRn[witness.Index[0]], wPow)) - //y_0R.Add(new(bn256.G1).Set(&y_0R), new(bn256.G1).ScalarMult(s.Publickeylist[witness.Index[0]], wPow)) - //DR.Add(new(bn256.G1).Set(&DR), new(bn256.G1).ScalarMult(s.D, wPow)) - - DR := new(bn256.G1).ScalarMult(C[0].Right, wPow) - DR = new(bn256.G1).Add(new(bn256.G1).Set(DR), new(bn256.G1).ScalarMult(global_pedersen_values.G, new(big.Int).Mod(new(big.Int).Neg(chi_bigint), bn256.Order))) - - gR := new(bn256.G1).ScalarMult(global_pedersen_values.G, new(big.Int).Mod(new(big.Int).Sub(wPow, psi_bigint), bn256.Order)) - - //gR.Add(new(bn256.G1).Set(&gR), new(bn256.G1).ScalarMult(params.G, wPow)) - - var p__, q__ []*big.Int - for i := 0; i < N; i++ { - - if i == witness.Index[0] { - p__ = append(p__, new(big.Int).Set(wPow)) - } else { - p__ = append(p__, new(big.Int)) - } - - if i == witness.Index[1] { - q__ = append(q__, new(big.Int).Set(wPow)) - } else { - q__ = append(q__, new(big.Int)) - } - } - p = p.Add(NewFieldVector(p__)) - q = q.Add(NewFieldVector(q__)) - - // klog.V(2).Infof("CrnR %s\n", CrnR.String()) - // klog.V(2).Infof("DR %s\n", DR.String()) - // klog.V(2).Infof("y_0R %s\n", y_0R.String()) - // klog.V(2).Infof("gR %s\n", gR.String()) - // klog.V(2).Infof("y_XR %s\n", y_XR.String()) - - // for i := range p.vector { - // klog.V(2).Infof("p %d %s \n", i, p.vector[i].Text(16)) - // } - - // for i := range q.vector { - // klog.V(2).Infof("q %d %s \n", i, q.vector[i].Text(16)) - // } - - y_p := Convolution(p, NewPointVector(s.Publickeylist)) - y_q := Convolution(q, NewPointVector(s.Publickeylist)) - - // for i := range y_p.vector { - // klog.V(2).Infof("y_p %d %s \n", i, y_p.vector[i].String()) - // } - // for i := range y_q.vector { - // klog.V(2).Infof("y_q %d %s \n", i, y_q.vector[i].String()) - // } - - vPow = new(big.Int).SetUint64(1) // already reduced - for i := 0; i < N; i++ { - - ypoly := y_p - if i%2 == 1 { - ypoly = y_q - } - y_XR.Add(new(bn256.G1).Set(&y_XR), new(bn256.G1).ScalarMult(ypoly.vector[i/2], vPow)) - - C_XR = C_XR.Add(ConstructElGamal(nil, new(bn256.G1).ScalarMult(ypoly.vector[i/2], vPow))) - - //fmt.Printf("y_XR[%d] %s\n",i, y_XR.String()) - //fmt.Printf("C_XR[%d] %s\n",i, C_XR.Right.String()) - if i > 0 { - vPow = new(big.Int).Mod(new(big.Int).Mul(vPow, v), bn256.Order) - } - } - - // klog.V(2).Infof("y_XR %s\n", y_XR.String()) - // klog.V(2).Infof("vPow %s\n", vPow.Text(16)) - // klog.V(2).Infof("v %s\n", v.Text(16)) - - k_sk := RandomScalarFixed() - k_r := RandomScalarFixed() - k_b := RandomScalarFixed() - k_tau := RandomScalarFixed() - - A_y := new(bn256.G1).ScalarMult(gR, k_sk) - A_D := new(bn256.G1).ScalarMult(params.G, k_r) - A_b := new(bn256.G1).ScalarMult(params.G, k_b) - t1 := new(bn256.G1).ScalarMult(CnR.Right, zs[1]) - d1 := new(bn256.G1).ScalarMult(DR, new(big.Int).Mod(new(big.Int).Neg(zs[0]), bn256.Order)) - d1 = new(bn256.G1).Add(d1, t1) - d1 = new(bn256.G1).ScalarMult(d1, k_sk) - A_b = new(bn256.G1).Add(A_b, d1) - - A_X := new(bn256.G1).ScalarMult(C_XR.Right, k_r) - - A_t := new(bn256.G1).ScalarMult(params.G, new(big.Int).Mod(new(big.Int).Neg(k_b), bn256.Order)) - A_t = new(bn256.G1).Add(A_t, new(bn256.G1).ScalarMult(params.H, k_tau)) - - A_u := new(bn256.G1) - - { - var input []byte - input = append(input, []byte(PROTOCOL_CONSTANT)...) - input = append(input, s.Roothash[:]...) - - point := HashToPoint(HashtoNumber(input)) - - A_u = new(bn256.G1).ScalarMult(point, k_sk) - } - - // klog.V(2).Infof("A_y %s\n", A_y.String()) - // klog.V(2).Infof("A_D %s\n", A_D.String()) - // klog.V(2).Infof("A_b %s\n", A_b.String()) - // klog.V(2).Infof("A_X %s\n", A_X.String()) - // klog.V(2).Infof("A_t %s\n", A_t.String()) - // klog.V(2).Infof("A_u %s\n", A_u.String()) - - { - var input []byte - input = append(input, ConvertBigIntToByte(x)...) - input = append(input, A_y.Marshal()...) - input = append(input, A_D.Marshal()...) - input = append(input, A_b.Marshal()...) - input = append(input, A_X.Marshal()...) - input = append(input, A_t.Marshal()...) - input = append(input, A_u.Marshal()...) - proof.c = reducedhash(input) - } - - proof.s_sk = new(big.Int).Mod(new(big.Int).Mul(proof.c, witness.SecretKey), bn256.Order) - proof.s_sk = new(big.Int).Mod(new(big.Int).Add(proof.s_sk, k_sk), bn256.Order) - - proof.s_r = new(big.Int).Mod(new(big.Int).Mul(proof.c, witness.R), bn256.Order) - proof.s_r = new(big.Int).Mod(new(big.Int).Add(proof.s_r, k_r), bn256.Order) - - // proof_c_neg := new(big.Int).Mod(new(big.Int).Neg(proof.c), bn256.Order) - // dummyA_X := new(bn256.G1).ScalarMult(&y_XR, proof.s_r) //, new(bn256.G1).ScalarMult(anonsupport.C_XR, proof_c_neg) ) - - // klog.V(2).Infof("dummyA_X %s\n", dummyA_X.String()) - // klog.V(2).Infof("s_r %s\n", proof.s_r.Text(16)) - // klog.V(2).Infof("C %s\n", proof.c.Text(16)) - // klog.V(2).Infof("C_neg %s\n", proof_c_neg.Text(16)) - - w_transfer := new(big.Int).Mod(new(big.Int).Mul(new(big.Int).SetUint64(uint64(witness.TransferAmount)), zs[0]), bn256.Order) - w_balance := new(big.Int).Mod(new(big.Int).Mul(new(big.Int).SetUint64(uint64(witness.Balance)), zs[1]), bn256.Order) - w_tmp := new(big.Int).Mod(new(big.Int).Add(w_transfer, w_balance), bn256.Order) - w_tmp = new(big.Int).Mod(new(big.Int).Mul(w_tmp, wPow), bn256.Order) - w_tmp = new(big.Int).Mod(new(big.Int).Mul(w_tmp, proof.c), bn256.Order) - proof.s_b = new(big.Int).Mod(new(big.Int).Add(w_tmp, k_b), bn256.Order) - - proof.s_tau = new(big.Int).Mod(new(big.Int).Mul(tauX, wPow), bn256.Order) - proof.s_tau = new(big.Int).Mod(new(big.Int).Mul(proof.s_tau, proof.c), bn256.Order) - proof.s_tau = new(big.Int).Mod(new(big.Int).Add(proof.s_tau, k_tau), bn256.Order) - - // klog.V(2).Infof("proof.c %s\n", proof.c.Text(16)) - // klog.V(2).Infof("proof.s_sk %s\n", proof.s_sk.Text(16)) - // klog.V(2).Infof("proof.s_r %s\n", proof.s_r.Text(16)) - // klog.V(2).Infof("proof.s_b %s\n", proof.s_b.Text(16)) - // klog.V(2).Infof("proof.s_tau %s\n", proof.s_tau.Text(16)) - - o := reducedhash(ConvertBigIntToByte(proof.c)) - - pvector := NewPedersenVectorCommitment() - pvector.H = new(bn256.G1).ScalarMult(pvector.H, o) - pvector.Hs = pvector.Hs.Hadamard(ys.Invert().vector) - pvector.gvalues = lPoly.Evaluate(x) - pvector.hvalues = rPoly.Evaluate(x) - proof.ip = NewInnerProductProofNew(pvector, o) - /* - - u_x := new(bn256.G1).ScalarMult(params.G, o) - P1 = new(bn256.G1).Add(P1, new(bn256.G1).ScalarMult(u_x, proof.that)) - klog.V(2).Infof("o %s\n", o.Text(16)) - klog.V(2).Infof("x %s\n", x.Text(16)) - klog.V(2).Infof("u_x %s\n", u_x.String()) - klog.V(2).Infof("p %s\n", P1.String()) - klog.V(2).Infof("hPrimes length %d\n", len(hPrimes.vector)) - - primebase := NewGeneratorParams3(u_x, params.Gs, hPrimes) // trigger sigma protocol - ipstatement := &IPStatement{PrimeBase: primebase, P: P1} - ipwitness := &IPWitness{L: lPoly.Evaluate(x), R: rPoly.Evaluate(x)} - - for i := range ipwitness.L.vector { - klog.V(2).Infof("L %d %s \n", i, ipwitness.L.vector[i].Text(16)) - } - - for i := range ipwitness.R.vector { - klog.V(2).Infof("R %d %s \n", i, ipwitness.R.vector[i].Text(16)) - } - - proof.ip = NewInnerProductProof(ipstatement, ipwitness, o) - */ - - return &proof - -} diff --git a/crypto/proof_innerproduct.go b/crypto/proof_innerproduct.go deleted file mode 100644 index 069e895..0000000 --- a/crypto/proof_innerproduct.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -//import "fmt" -import "math" -import "math/big" -import "bytes" - -//import "crypto/rand" -//import "encoding/hex" - -import "github.com/deroproject/derohe/crypto/bn256" - -//import "golang.org/x/crypto/sha3" - -// basically the Σ-protocol -type InnerProduct struct { - a, b *big.Int - ls, rs []*bn256.G1 -} - -func (ip *InnerProduct) Size() int { - return FIELDELEMENT_SIZE + FIELDELEMENT_SIZE + 1 + len(ip.ls)*POINT_SIZE + len(ip.rs)*POINT_SIZE -} - -// since our bulletproofs are 128 bits, we can get away hard coded 7 entries -func (ip *InnerProduct) Serialize(w *bytes.Buffer) { - w.Write(ConvertBigIntToByte(ip.a)) - w.Write(ConvertBigIntToByte(ip.b)) - // w.WriteByte(byte(len(ip.ls))) // we can skip this byte also, why not skip it - - // fmt.Printf("inner proof length byte %d\n",len(ip.ls)) - for i := range ip.ls { - w.Write(ip.ls[i].EncodeCompressed()) - w.Write(ip.rs[i].EncodeCompressed()) - } -} - -func (ip *InnerProduct) Deserialize(r *bytes.Reader) (err error) { - - var buf [32]byte - var bufp [33]byte - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - ip.a = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - - if n, err := r.Read(buf[:]); n == 32 && err == nil { - ip.b = new(big.Int).SetBytes(buf[:]) - } else { - return err - } - - length := 7 - - ip.ls = ip.ls[:0] - ip.rs = ip.rs[:0] - for i := 0; i < length; i++ { - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - - ip.ls = append(ip.ls, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - - ip.rs = append(ip.rs, &p) - } else { - return err - } - - } - - return err -} - -func NewInnerProductProof(ips *IPStatement, witness *IPWitness, salt *big.Int) *InnerProduct { - var ip InnerProduct - - ip.generateInnerProductProof(ips.PrimeBase, ips.P, witness.L, witness.R, salt) - return &ip -} - -func (ip *InnerProduct) generateInnerProductProof(base *GeneratorParams, P *bn256.G1, as, bs *FieldVector, prev_challenge *big.Int) { - n := as.Length() - - if n == 1 { // the proof is done, ls,rs are already in place - ip.a = as.vector[0] - ip.b = bs.vector[0] - return - } - - nPrime := n / 2 - asLeft := as.Slice(0, nPrime) - asRight := as.Slice(nPrime, n) - bsLeft := bs.Slice(0, nPrime) - bsRight := bs.Slice(nPrime, n) - gLeft := base.Gs.Slice(0, nPrime) - gRight := base.Gs.Slice(nPrime, n) - hLeft := base.Hs.Slice(0, nPrime) - hRight := base.Hs.Slice(nPrime, n) - - cL := asLeft.InnerProduct(bsRight) - cR := asRight.InnerProduct(bsLeft) - - u := base.H - L := new(bn256.G1).Add(gRight.Commit(asLeft.vector), hLeft.Commit(bsRight.vector)) - L = new(bn256.G1).Add(L, new(bn256.G1).ScalarMult(u, cL)) - - R := new(bn256.G1).Add(gLeft.Commit(asRight.vector), hRight.Commit(bsLeft.vector)) - R = new(bn256.G1).Add(R, new(bn256.G1).ScalarMult(u, cR)) - - ip.ls = append(ip.ls, L) - ip.rs = append(ip.rs, R) - - var input []byte - input = append(input, ConvertBigIntToByte(prev_challenge)...) - input = append(input, L.Marshal()...) - input = append(input, R.Marshal()...) - x := reducedhash(input) - - xinv := new(big.Int).ModInverse(x, bn256.Order) - - gPrime := gLeft.Times(xinv).Add(gRight.Times(x)) - hPrime := hLeft.Times(x).Add(hRight.Times(xinv)) - aPrime := asLeft.Times(x).Add(asRight.Times(xinv)) - bPrime := bsLeft.Times(xinv).Add(bsRight.Times(x)) - - basePrime := NewGeneratorParams3(u, gPrime, hPrime) - - PPrimeL := new(bn256.G1).ScalarMult(L, new(big.Int).Mod(new(big.Int).Mul(x, x), bn256.Order)) //L * (x*x) - PPrimeR := new(bn256.G1).ScalarMult(R, new(big.Int).Mod(new(big.Int).Mul(xinv, xinv), bn256.Order)) //R * (xinv*xinv) - - PPrime := new(bn256.G1).Add(PPrimeL, PPrimeR) - PPrime = new(bn256.G1).Add(PPrime, P) - - ip.generateInnerProductProof(basePrime, PPrime, aPrime, bPrime, x) - - return - -} - -func NewInnerProductProofNew(p *PedersenVectorCommitment, salt *big.Int) *InnerProduct { - var ip InnerProduct - - ip.generateInnerProductProofNew(p, p.gvalues, p.hvalues, salt) - return &ip -} - -func (ip *InnerProduct) generateInnerProductProofNew(p *PedersenVectorCommitment, as, bs *FieldVector, prev_challenge *big.Int) { - n := as.Length() - - if n == 1 { // the proof is done, ls,rs are already in place - ip.a = as.vector[0] - ip.b = bs.vector[0] - return - } - - nPrime := n / 2 - asLeft := as.Slice(0, nPrime) - asRight := as.Slice(nPrime, n) - bsLeft := bs.Slice(0, nPrime) - bsRight := bs.Slice(nPrime, n) - - gsLeft := p.Gs.Slice(0, nPrime) - gsRight := p.Gs.Slice(nPrime, n) - hsLeft := p.Hs.Slice(0, nPrime) - hsRight := p.Hs.Slice(nPrime, n) - - cL := asLeft.InnerProduct(bsRight) - cR := asRight.InnerProduct(bsLeft) - - /*u := base.H - L := new(bn256.G1).Add(gRight.Commit(asLeft.vector), hLeft.Commit(bsRight.vector)) - L = new(bn256.G1).Add(L, new(bn256.G1).ScalarMult(u, cL)) - - R := new(bn256.G1).Add(gLeft.Commit(asRight.vector), hRight.Commit(bsLeft.vector)) - R = new(bn256.G1).Add(R, new(bn256.G1).ScalarMult(u, cR)) - */ - - Lpart := new(bn256.G1).Add(gsRight.MultiExponentiate(asLeft), hsLeft.MultiExponentiate(bsRight)) - L := new(bn256.G1).Add(Lpart, new(bn256.G1).ScalarMult(p.H, cL)) - - Rpart := new(bn256.G1).Add(gsLeft.MultiExponentiate(asRight), hsRight.MultiExponentiate(bsLeft)) - R := new(bn256.G1).Add(Rpart, new(bn256.G1).ScalarMult(p.H, cR)) - - ip.ls = append(ip.ls, L) - ip.rs = append(ip.rs, R) - - var input []byte - input = append(input, ConvertBigIntToByte(prev_challenge)...) - input = append(input, L.Marshal()...) - input = append(input, R.Marshal()...) - x := reducedhash(input) - - xInv := new(big.Int).ModInverse(x, bn256.Order) - - p.Gs = gsLeft.Times(xInv).Add(gsRight.Times(x)) - p.Hs = hsLeft.Times(x).Add(hsRight.Times(xInv)) - asPrime := asLeft.Times(x).Add(asRight.Times(xInv)) - bsPrime := bsLeft.Times(xInv).Add(bsRight.Times(x)) - - ip.generateInnerProductProofNew(p, asPrime, bsPrime, x) - - return - -} - -func (ip *InnerProduct) Verify(hs []*bn256.G1, u, P *bn256.G1, salt *big.Int, gp *GeneratorParams) bool { - log_n := uint(len(ip.ls)) - - if len(ip.ls) != len(ip.rs) { // length must be same - return false - } - n := uint(math.Pow(2, float64(log_n))) - - o := salt - var challenges []*big.Int - for i := uint(0); i < log_n; i++ { - - var input []byte - input = append(input, ConvertBigIntToByte(o)...) - input = append(input, ip.ls[i].Marshal()...) - input = append(input, ip.rs[i].Marshal()...) - o = reducedhash(input) - challenges = append(challenges, o) - - o_inv := new(big.Int).ModInverse(o, bn256.Order) - - PPrimeL := new(bn256.G1).ScalarMult(ip.ls[i], new(big.Int).Mod(new(big.Int).Mul(o, o), bn256.Order)) //L * (x*x) - PPrimeR := new(bn256.G1).ScalarMult(ip.rs[i], new(big.Int).Mod(new(big.Int).Mul(o_inv, o_inv), bn256.Order)) //L * (x*x) - - PPrime := new(bn256.G1).Add(PPrimeL, PPrimeR) - P = new(bn256.G1).Add(PPrime, P) - } - - exp := new(big.Int).SetUint64(1) - for i := uint(0); i < log_n; i++ { - exp = new(big.Int).Mod(new(big.Int).Mul(exp, challenges[i]), bn256.Order) - } - - exp_inv := new(big.Int).ModInverse(exp, bn256.Order) - - exponents := make([]*big.Int, n, n) - - exponents[0] = exp_inv // initializefirst element - - bits := make([]bool, n, n) - for i := uint(0); i < n/2; i++ { - for j := uint(0); (1< 0 { - anonsupport.vPow = new(big.Int).Mod(new(big.Int).Mul(anonsupport.vPow, anonsupport.v), bn256.Order) - // klog.V(2).Infof("vPow %s\n", anonsupport.vPow.Text(16)) - } - } - - // klog.V(2).Infof("vPow %s\n", anonsupport.vPow.Text(16)) - // klog.V(2).Infof("v %s\n", anonsupport.v.Text(16)) - - anonsupport.wPow = new(big.Int).SetUint64(1) - anonsupport.gR = new(bn256.G1) - anonsupport.gR.Unmarshal(zeroes[:]) - anonsupport.DR = new(bn256.G1) - anonsupport.DR.Unmarshal(zeroes[:]) - - for i := 0; i < m; i++ { - wPow_neg := new(big.Int).Mod(new(big.Int).Neg(anonsupport.wPow), bn256.Order) - anonsupport.CLnR.Add(new(bn256.G1).Set(anonsupport.CLnR), new(bn256.G1).ScalarMult(proof.CLnG[i], wPow_neg)) - anonsupport.CRnR.Add(new(bn256.G1).Set(anonsupport.CRnR), new(bn256.G1).ScalarMult(proof.CRnG[i], wPow_neg)) - - anonsupport.CR[0][0].Add(new(bn256.G1).Set(anonsupport.CR[0][0]), new(bn256.G1).ScalarMult(proof.C_0G[i], wPow_neg)) - anonsupport.DR.Add(new(bn256.G1).Set(anonsupport.DR), new(bn256.G1).ScalarMult(proof.DG[i], wPow_neg)) - anonsupport.yR[0][0].Add(new(bn256.G1).Set(anonsupport.yR[0][0]), new(bn256.G1).ScalarMult(proof.y_0G[i], wPow_neg)) - anonsupport.gR.Add(new(bn256.G1).Set(anonsupport.gR), new(bn256.G1).ScalarMult(proof.gG[i], wPow_neg)) - - anonsupport.C_XR.Add(new(bn256.G1).Set(anonsupport.C_XR), new(bn256.G1).ScalarMult(proof.C_XG[i], wPow_neg)) - anonsupport.y_XR.Add(new(bn256.G1).Set(anonsupport.y_XR), new(bn256.G1).ScalarMult(proof.y_XG[i], wPow_neg)) - - anonsupport.wPow = new(big.Int).Mod(new(big.Int).Mul(anonsupport.wPow, anonsupport.w), bn256.Order) - - } - // klog.V(2).Infof("qCrnR %s\n", anonsupport.CRnR.String()) - - anonsupport.DR.Add(new(bn256.G1).Set(anonsupport.DR), new(bn256.G1).ScalarMult(s.D, anonsupport.wPow)) - anonsupport.gR.Add(new(bn256.G1).Set(anonsupport.gR), new(bn256.G1).ScalarMult(gparams.G, anonsupport.wPow)) - anonsupport.C_XR.Add(new(bn256.G1).Set(anonsupport.C_XR), new(bn256.G1).ScalarMult(gparams.G, new(big.Int).Mod(new(big.Int).Mul(new(big.Int).SetUint64(s.Fees), anonsupport.wPow), bn256.Order))) - - //anonAuxiliaries.C_XR = anonAuxiliaries.C_XR.add(Utils.g().mul(Utils.fee().mul(anonAuxiliaries.wPow))); // this line is new - - // at this point, these parameters are comparable with proof generator - // klog.V(2).Infof("CLnR %s\n", anonsupport.CLnR.String()) - // klog.V(2).Infof("qCrnR %s\n", anonsupport.CRnR.String()) - // klog.V(2).Infof("DR %s\n", anonsupport.DR.String()) - // klog.V(2).Infof("gR %s\n", anonsupport.gR.String()) - // klog.V(2).Infof("C_XR %s\n", anonsupport.C_XR.String()) - // klog.V(2).Infof("y_XR %s\n", anonsupport.y_XR.String()) - - protsupport.y = reducedhash(ConvertBigIntToByte(anonsupport.w)) - protsupport.ys = append(protsupport.ys, new(big.Int).SetUint64(1)) - protsupport.k = new(big.Int).SetUint64(1) - for i := 1; i < 128; i++ { - protsupport.ys = append(protsupport.ys, new(big.Int).Mod(new(big.Int).Mul(protsupport.ys[i-1], protsupport.y), bn256.Order)) - protsupport.k = new(big.Int).Mod(new(big.Int).Add(protsupport.k, protsupport.ys[i]), bn256.Order) - } - - protsupport.z = reducedhash(ConvertBigIntToByte(protsupport.y)) - protsupport.zs = []*big.Int{new(big.Int).Exp(protsupport.z, new(big.Int).SetUint64(2), bn256.Order), new(big.Int).Exp(protsupport.z, new(big.Int).SetUint64(3), bn256.Order)} - - protsupport.zSum = new(big.Int).Mod(new(big.Int).Add(protsupport.zs[0], protsupport.zs[1]), bn256.Order) - protsupport.zSum = new(big.Int).Mod(new(big.Int).Mul(new(big.Int).Set(protsupport.zSum), protsupport.z), bn256.Order) - - // klog.V(2).Infof("zsum %s\n ", protsupport.zSum.Text(16)) - - z_z0 := new(big.Int).Mod(new(big.Int).Sub(protsupport.z, protsupport.zs[0]), bn256.Order) - protsupport.k = new(big.Int).Mod(new(big.Int).Mul(protsupport.k, z_z0), bn256.Order) - - proof_2_64, _ := new(big.Int).SetString("18446744073709551616", 10) - zsum_pow := new(big.Int).Mod(new(big.Int).Mul(protsupport.zSum, proof_2_64), bn256.Order) - zsum_pow = new(big.Int).Mod(new(big.Int).Sub(zsum_pow, protsupport.zSum), bn256.Order) - protsupport.k = new(big.Int).Mod(new(big.Int).Sub(protsupport.k, zsum_pow), bn256.Order) - - protsupport.t = new(big.Int).Mod(new(big.Int).Sub(proof.that, protsupport.k), bn256.Order) // t = tHat - delta(y, z) - - // klog.V(2).Infof("that %s\n ", proof.that.Text(16)) - // klog.V(2).Infof("zk %s\n ", protsupport.k.Text(16)) - - for i := 0; i < 64; i++ { - protsupport.twoTimesZSquared[i] = new(big.Int).Mod(new(big.Int).Mul(protsupport.zs[0], new(big.Int).SetUint64(uint64(math.Pow(2, float64(i))))), bn256.Order) - protsupport.twoTimesZSquared[64+i] = new(big.Int).Mod(new(big.Int).Mul(protsupport.zs[1], new(big.Int).SetUint64(uint64(math.Pow(2, float64(i))))), bn256.Order) - } - - // for i := 0; i < 128; i++ { - // klog.V(2).Infof("zsq %d %s", i, protsupport.twoTimesZSquared[i].Text(16)) - // } - - x := new(big.Int) - - { - var input []byte - input = append(input, ConvertBigIntToByte(protsupport.z)...) // tie intermediates/commit - input = append(input, proof.T_1.Marshal()...) - input = append(input, proof.T_2.Marshal()...) - x = reducedhash(input) - } - - xsq := new(big.Int).Mod(new(big.Int).Mul(x, x), bn256.Order) - protsupport.tEval = new(bn256.G1).ScalarMult(proof.T_1, x) - protsupport.tEval.Add(new(bn256.G1).Set(protsupport.tEval), new(bn256.G1).ScalarMult(proof.T_2, xsq)) - - // klog.V(2).Infof("protsupport.tEval %s\n", protsupport.tEval.String()) - - proof_c_neg := new(big.Int).Mod(new(big.Int).Neg(proof.c), bn256.Order) - - sigmasupport.A_y = new(bn256.G1).Add(new(bn256.G1).ScalarMult(anonsupport.gR, proof.s_sk), new(bn256.G1).ScalarMult(anonsupport.yR[0][0], proof_c_neg)) - sigmasupport.A_D = new(bn256.G1).Add(new(bn256.G1).ScalarMult(gparams.G, proof.s_r), new(bn256.G1).ScalarMult(s.D, proof_c_neg)) - - zs0_neg := new(big.Int).Mod(new(big.Int).Neg(protsupport.zs[0]), bn256.Order) - - left := new(bn256.G1).ScalarMult(anonsupport.DR, zs0_neg) - left.Add(new(bn256.G1).Set(left), new(bn256.G1).ScalarMult(anonsupport.CRnR, protsupport.zs[1])) - left = new(bn256.G1).ScalarMult(new(bn256.G1).Set(left), proof.s_sk) - - // TODO mid seems wrong - amount_fees := new(big.Int).SetUint64(s.Fees) - mid := new(bn256.G1).ScalarMult(G, new(big.Int).Mod(new(big.Int).Mul(amount_fees, anonsupport.wPow), bn256.Order)) - mid.Add(new(bn256.G1).Set(mid), new(bn256.G1).Set(anonsupport.CR[0][0])) - - right := new(bn256.G1).ScalarMult(mid, zs0_neg) - right.Add(new(bn256.G1).Set(right), new(bn256.G1).ScalarMult(anonsupport.CLnR, protsupport.zs[1])) - right = new(bn256.G1).ScalarMult(new(bn256.G1).Set(right), proof_c_neg) - - sigmasupport.A_b = new(bn256.G1).ScalarMult(gparams.G, proof.s_b) - temp := new(bn256.G1).Add(left, right) - sigmasupport.A_b.Add(new(bn256.G1).Set(sigmasupport.A_b), temp) - - //- sigmaAuxiliaries.A_b = Utils.g().mul(proof.s_b).add(anonAuxiliaries.DR.mul(zetherAuxiliaries.zs[0].neg()).add(anonAuxiliaries.CRnR.mul(zetherAuxiliaries.zs[1])).mul(proof.s_sk).add(anonAuxiliaries.CR[0][0] .mul(zetherAuxiliaries.zs[0].neg()).add(anonAuxiliaries.CLnR.mul(zetherAuxiliaries.zs[1])).mul(proof.c.neg()))); - //+ sigmaAuxiliaries.A_b = Utils.g().mul(proof.s_b).add(anonAuxiliaries.DR.mul(zetherAuxiliaries.zs[0].neg()).add(anonAuxiliaries.CRnR.mul(zetherAuxiliaries.zs[1])).mul(proof.s_sk).add(anonAuxiliaries.CR[0][0].add(Utils.g().mul(Utils.fee().mul(anonAuxiliaries.wPow))).mul(zetherAuxiliaries.zs[0].neg()).add(anonAuxiliaries.CLnR.mul(zetherAuxiliaries.zs[1])).mul(proof.c.neg()))); - - //var fees bn256.G1 - //fees.ScalarMult(G, new(big.Int).SetInt64(int64( -1 ))) - //anonsupport.C_XR.Add( new(bn256.G1).Set(anonsupport.C_XR), &fees) - - sigmasupport.A_X = new(bn256.G1).Add(new(bn256.G1).ScalarMult(anonsupport.y_XR, proof.s_r), new(bn256.G1).ScalarMult(anonsupport.C_XR, proof_c_neg)) - - proof_s_b_neg := new(big.Int).Mod(new(big.Int).Neg(proof.s_b), bn256.Order) - - sigmasupport.A_t = new(bn256.G1).ScalarMult(gparams.G, protsupport.t) - sigmasupport.A_t.Add(new(bn256.G1).Set(sigmasupport.A_t), new(bn256.G1).Neg(protsupport.tEval)) - sigmasupport.A_t = new(bn256.G1).ScalarMult(sigmasupport.A_t, new(big.Int).Mod(new(big.Int).Mul(proof.c, anonsupport.wPow), bn256.Order)) - sigmasupport.A_t.Add(new(bn256.G1).Set(sigmasupport.A_t), new(bn256.G1).ScalarMult(gparams.H, proof.s_tau)) - sigmasupport.A_t.Add(new(bn256.G1).Set(sigmasupport.A_t), new(bn256.G1).ScalarMult(gparams.G, proof_s_b_neg)) - // klog.V(2).Infof("t %s\n ", protsupport.t.Text(16)) - // klog.V(2).Infof("protsupport.tEval %s\n", protsupport.tEval.String()) - - { - var input []byte - input = append(input, []byte(PROTOCOL_CONSTANT)...) - input = append(input, s.Roothash[:]...) - - point := HashToPoint(HashtoNumber(input)) - - sigmasupport.A_u = new(bn256.G1).ScalarMult(point, proof.s_sk) - sigmasupport.A_u.Add(new(bn256.G1).Set(sigmasupport.A_u), new(bn256.G1).ScalarMult(proof.u, proof_c_neg)) - } - - // klog.V(2).Infof("A_y %s\n", sigmasupport.A_y.String()) - // klog.V(2).Infof("A_D %s\n", sigmasupport.A_D.String()) - // klog.V(2).Infof("A_b %s\n", sigmasupport.A_b.String()) - // klog.V(2).Infof("A_X %s\n", sigmasupport.A_X.String()) - // klog.V(2).Infof("A_t %s\n", sigmasupport.A_t.String()) - // klog.V(2).Infof("A_u %s\n", sigmasupport.A_u.String()) - - { - var input []byte - input = append(input, ConvertBigIntToByte(x)...) - input = append(input, sigmasupport.A_y.Marshal()...) - input = append(input, sigmasupport.A_D.Marshal()...) - input = append(input, sigmasupport.A_b.Marshal()...) - input = append(input, sigmasupport.A_X.Marshal()...) - input = append(input, sigmasupport.A_t.Marshal()...) - input = append(input, sigmasupport.A_u.Marshal()...) - if reducedhash(input).Text(16) != proof.c.Text(16) { // we must fail here - //panic("C calculation failed") - // klog.Warning("C calculation failed") - return false - } - } - - o := reducedhash(ConvertBigIntToByte(proof.c)) - - u_x := new(bn256.G1).ScalarMult(gparams.H, o) - - var hPrimes []*bn256.G1 - hPrimeSum := new(bn256.G1) - - hPrimeSum.Unmarshal(zeroes[:]) - for i := 0; i < 128; i++ { - hPrimes = append(hPrimes, new(bn256.G1).ScalarMult(gparams.Hs.vector[i], new(big.Int).ModInverse(protsupport.ys[i], bn256.Order))) - - // klog.V(2).Infof("hPrimes %d %s\n", i, hPrimes[i].String()) - - tmp := new(big.Int).Mod(new(big.Int).Mul(protsupport.ys[i], protsupport.z), bn256.Order) - tmp = new(big.Int).Mod(new(big.Int).Add(tmp, protsupport.twoTimesZSquared[i]), bn256.Order) - - hPrimeSum = new(bn256.G1).Add(hPrimeSum, new(bn256.G1).ScalarMult(hPrimes[i], tmp)) - - } - - P := new(bn256.G1).Add(proof.BA, new(bn256.G1).ScalarMult(proof.BS, x)) - P = new(bn256.G1).Add(P, new(bn256.G1).ScalarMult(gparams.GSUM, new(big.Int).Mod(new(big.Int).Neg(protsupport.z), bn256.Order))) - P = new(bn256.G1).Add(P, hPrimeSum) - - P = new(bn256.G1).Add(P, new(bn256.G1).ScalarMult(gparams.H, new(big.Int).Mod(new(big.Int).Neg(proof.mu), bn256.Order))) - P = new(bn256.G1).Add(P, new(bn256.G1).ScalarMult(u_x, new(big.Int).Mod(new(big.Int).Set(proof.that), bn256.Order))) - - // klog.V(2).Infof("P %s\n", P.String()) - - if !proof.ip.Verify(hPrimes, u_x, P, o, gparams) { - // klog.Warning("inner proof failed") - return false - } - - // klog.V(2).Infof("proof %s\n", proof.String()) - // panic("proof successful") - - // klog.V(2).Infof("Proof successful verified\n") - - return true - -} - -/* -func (proof *Proof) String() string { - klog.V(1).Infof("proof BA %s\n", proof.BA.String()) - klog.V(1).Infof("proof BS %s\n", proof.BS.String()) - klog.V(1).Infof("proof A %s\n", proof.A.String()) - klog.V(1).Infof("proof B %s\n", proof.B.String()) - - for i := range proof.CLnG { - klog.V(1).Infof("CLnG %d %s \n", i, proof.CLnG[i].String()) - } - for i := range proof.CRnG { - klog.V(1).Infof("CRnG %d %s \n", i, proof.CRnG[i].String()) - } - - for i := range proof.C_0G { - klog.V(1).Infof("C_0G %d %s \n", i, proof.C_0G[i].String()) - } - for i := range proof.DG { - klog.V(1).Infof("DG %d %s \n", i, proof.DG[i].String()) - } - for i := range proof.y_0G { - klog.V(1).Infof("y_0G %d %s \n", i, proof.y_0G[i].String()) - } - for i := range proof.gG { - klog.V(1).Infof("gG %d %s \n", i, proof.gG[i].String()) - } - - for i := range proof.C_XG { - klog.V(1).Infof("C_XG %d %s \n", i, proof.C_XG[i].String()) - } - for i := range proof.y_XG { - klog.V(1).Infof("y_XG %d %s \n", i, proof.y_XG[i].String()) - } - - //for i := range proof.tCommits.vector { - // klog.V(1).Infof("tCommits %d %s \n", i, proof.tCommits.vector[i].String()) - //} - - klog.V(1).Infof("proof z_A %s\n", proof.z_A.Text(16)) - klog.V(1).Infof("proof that %s\n", proof.that.Text(16)) - klog.V(1).Infof("proof mu %s\n", proof.mu.Text(16)) - klog.V(1).Infof("proof C %s\n", proof.c.Text(16)) - klog.V(1).Infof("proof s_sk %s\n", proof.s_sk.Text(16)) - klog.V(1).Infof("proof s_r %s\n", proof.s_r.Text(16)) - klog.V(1).Infof("proof s_b %s\n", proof.s_b.Text(16)) - klog.V(1).Infof("proof s_tau %s\n", proof.s_tau.Text(16)) - - return "" - -} -*/ -func assemblepolynomials(f [][2]*big.Int) [][2]*big.Int { - m := len(f) / 2 - N := int(math.Pow(2, float64(m))) - result := make([][2]*big.Int, N, N) - - for i := 0; i < 2; i++ { - half := recursivepolynomials(i*m, (i+1)*m, new(big.Int).SetInt64(1), f) - for j := 0; j < N; j++ { - result[j][i] = half[j] - } - } - return result -} - -func recursivepolynomials(baseline, current int, accum *big.Int, f [][2]*big.Int) []*big.Int { - size := int(math.Pow(2, float64(current-baseline))) - - result := make([]*big.Int, size, size) - if current == baseline { - result[0] = accum - return result - } - current-- - - left := recursivepolynomials(baseline, current, new(big.Int).Mod(new(big.Int).Mul(accum, f[current][0]), bn256.Order), f) - right := recursivepolynomials(baseline, current, new(big.Int).Mod(new(big.Int).Mul(accum, f[current][1]), bn256.Order), f) - for i := 0; i < size/2; i++ { - result[i] = left[i] - result[i+size/2] = right[i] - } - - return result -} diff --git a/crypto/protocol_structures.go b/crypto/protocol_structures.go deleted file mode 100644 index f286f4f..0000000 --- a/crypto/protocol_structures.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -// import "fmt" -import "bytes" -import "encoding/binary" -import "math/big" -import "github.com/deroproject/derohe/crypto/bn256" - -type Statement struct { - RingSize uint64 - CLn []*bn256.G1 - CRn []*bn256.G1 - Publickeylist []*bn256.G1 // Todo these can be skipped and collected back later on from the chain, this will save ringsize * POINTSIZE bytes - Publickeylist_compressed [][33]byte // compressed format for public keys NOTE: only valid in deserialized transactions - C []*bn256.G1 // commitments - D *bn256.G1 - Fees uint64 - - Roothash [32]byte // note roothash contains the merkle root hash of chain, when it was build -} - -type Witness struct { - SecretKey *big.Int - R *big.Int - TransferAmount uint64 // total value being transferred - Balance uint64 // whatever is the the amount left after transfer - Index []int // index of sender in the public key list - -} - -func (s *Statement) Serialize(w *bytes.Buffer) { - buf := make([]byte, binary.MaxVarintLen64) - //n := binary.PutUvarint(buf, uint64(len(s.Publickeylist))) - //w.Write(buf[:n]) - - power := byte(GetPowerof2(len(s.Publickeylist))) // len(s.Publickeylist) is always power of 2 - w.WriteByte(power) - - n := binary.PutUvarint(buf, s.Fees) - w.Write(buf[:n]) - - w.Write(s.D.EncodeCompressed()) - for i := 0; i < len(s.Publickeylist); i++ { - // w.Write( s.CLn[i].EncodeCompressed()) - // w.Write( s.CRn[i].EncodeCompressed()) - w.Write(s.Publickeylist[i].EncodeCompressed()) - w.Write(s.C[i].EncodeCompressed()) - } - - w.Write(s.Roothash[:]) - -} - -func (s *Statement) Deserialize(r *bytes.Reader) error { - - var err error - //var buf [32]byte - var bufp [33]byte - - length, err := r.ReadByte() - if err != nil { - return err - } - - s.RingSize = 1 << length - - s.Fees, err = binary.ReadUvarint(r) - if err != nil { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - s.D = &p - } else { - return err - } - - s.CLn = s.CLn[:0] - s.CRn = s.CRn[:0] - s.Publickeylist = s.Publickeylist[:0] - s.Publickeylist_compressed = s.Publickeylist_compressed[:0] - s.C = s.C[:0] - - for i := uint64(0); i < s.RingSize; i++ { - - /* - if n,err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - s.CLn = append(s.CLn,&p) - }else{ - return err - } - - if n,err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - s.CRn = append(s.CRn,&p) - }else{ - return err - } - */ - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - var pcopy [33]byte - copy(pcopy[:], bufp[:]) - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - s.Publickeylist_compressed = append(s.Publickeylist_compressed, pcopy) - s.Publickeylist = append(s.Publickeylist, &p) - } else { - return err - } - - if n, err := r.Read(bufp[:]); n == 33 && err == nil { - var p bn256.G1 - if err = p.DecodeCompressed(bufp[:]); err != nil { - return err - } - s.C = append(s.C, &p) - } else { - return err - } - - } - - if n, err := r.Read(s.Roothash[:]); n == 32 && err == nil { - - } else { - return err - } - - return nil - -} - -/* -type Proof struct { - BA *bn256.G1 - BS *bn256.G1 - A *bn256.G1 - B *bn256.G1 - - CLnG, CRnG, C_0G, DG, y_0G, gG, C_XG, y_XG []*bn256.G1 - - u *bn256.G1 - - f *FieldVector - - z_A *big.Int - - T_1 *bn256.G1 - T_2 *bn256.G1 - - that *big.Int - mu *big.Int - - c *big.Int - s_sk, s_r, s_b, s_tau *big.Int - - //ip *InnerProduct -} -*/ diff --git a/crypto/random.go b/crypto/random.go deleted file mode 100644 index b20ad2e..0000000 --- a/crypto/random.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017-2021 DERO Project. All rights reserved. -// Use of this source code in any form is governed by RESEARCH license. -// license can be found in the LICENSE file. -// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 -// -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package crypto - -import "math/big" -import "crypto/rand" -import "github.com/deroproject/derohe/crypto/bn256" - -func RandomScalar() *big.Int { - - for { - a, _ := rand.Int(rand.Reader, bn256.Order) - if a.Sign() > 0 { - return a - } - - } -} - -// this will return fixed random scalar -func RandomScalarFixed() *big.Int { - //return new(big.Int).Set(fixed) - - return RandomScalar() -} - -type KeyPair struct { - x *big.Int // secret key - y *bn256.G1 // public key -} diff --git a/crypto/sha3/doc.go b/crypto/sha3/doc.go deleted file mode 100644 index c06a330..0000000 --- a/crypto/sha3/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package sha3 implements the SHA-3 fixed-output-length hash functions and -// the SHAKE variable-output-length hash functions defined by FIPS-202. -// -// Both types of hash function use the "sponge" construction and the Keccak -// permutation. For a detailed specification see http://keccak.noekeon.org/ -// -// -// Guidance -// -// If you aren't sure what function you need, use SHAKE256 with at least 64 -// bytes of output. The SHAKE instances are faster than the SHA3 instances; -// the latter have to allocate memory to conform to the hash.Hash interface. -// -// If you need a secret-key MAC (message authentication code), prepend the -// secret key to the input, hash with SHAKE256 and read at least 32 bytes of -// output. -// -// -// Security strengths -// -// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security -// strength against preimage attacks of x bits. Since they only produce "x" -// bits of output, their collision-resistance is only "x/2" bits. -// -// The SHAKE-256 and -128 functions have a generic security strength of 256 and -// 128 bits against all attacks, provided that at least 2x bits of their output -// is used. Requesting more than 64 or 32 bytes of output, respectively, does -// not increase the collision-resistance of the SHAKE functions. -// -// -// The sponge construction -// -// A sponge builds a pseudo-random function from a public pseudo-random -// permutation, by applying the permutation to a state of "rate + capacity" -// bytes, but hiding "capacity" of the bytes. -// -// A sponge starts out with a zero state. To hash an input using a sponge, up -// to "rate" bytes of the input are XORed into the sponge's state. The sponge -// is then "full" and the permutation is applied to "empty" it. This process is -// repeated until all the input has been "absorbed". The input is then padded. -// The digest is "squeezed" from the sponge in the same way, except that output -// is copied out instead of input being XORed in. -// -// A sponge is parameterized by its generic security strength, which is equal -// to half its capacity; capacity + rate is equal to the permutation's width. -// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means -// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. -// -// -// Recommendations -// -// The SHAKE functions are recommended for most new uses. They can produce -// output of arbitrary length. SHAKE256, with an output length of at least -// 64 bytes, provides 256-bit security against all attacks. The Keccak team -// recommends it for most applications upgrading from SHA2-512. (NIST chose a -// much stronger, but much slower, sponge instance for SHA3-512.) -// -// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. -// They produce output of the same length, with the same security strengths -// against all attacks. This means, in particular, that SHA3-256 only has -// 128-bit collision resistance, because its output length is 32 bytes. -package sha3 diff --git a/crypto/sha3/hashes.go b/crypto/sha3/hashes.go deleted file mode 100644 index 0d8043f..0000000 --- a/crypto/sha3/hashes.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This file provides functions for creating instances of the SHA-3 -// and SHAKE hash functions, as well as utility functions for hashing -// bytes. - -import ( - "hash" -) - -// New224 creates a new SHA3-224 hash. -// Its generic security strength is 224 bits against preimage attacks, -// and 112 bits against collision attacks. -func New224() hash.Hash { - if h := new224Asm(); h != nil { - return h - } - return &state{rate: 144, outputLen: 28, dsbyte: 0x06} -} - -// New256 creates a new SHA3-256 hash. -// Its generic security strength is 256 bits against preimage attacks, -// and 128 bits against collision attacks. -func New256() hash.Hash { - if h := new256Asm(); h != nil { - return h - } - return &state{rate: 136, outputLen: 32, dsbyte: 0x06} -} - -// New384 creates a new SHA3-384 hash. -// Its generic security strength is 384 bits against preimage attacks, -// and 192 bits against collision attacks. -func New384() hash.Hash { - if h := new384Asm(); h != nil { - return h - } - return &state{rate: 104, outputLen: 48, dsbyte: 0x06} -} - -// New512 creates a new SHA3-512 hash. -// Its generic security strength is 512 bits against preimage attacks, -// and 256 bits against collision attacks. -func New512() hash.Hash { - if h := new512Asm(); h != nil { - return h - } - return &state{rate: 72, outputLen: 64, dsbyte: 0x06} -} - -// NewLegacyKeccak256 creates a new Keccak-256 hash. -// -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New256 instead. -func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } - -// NewLegacyKeccak512 creates a new Keccak-512 hash. -// -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New512 instead. -func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } - -// Sum224 returns the SHA3-224 digest of the data. -func Sum224(data []byte) (digest [28]byte) { - h := New224() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum256 returns the SHA3-256 digest of the data. -func Sum256(data []byte) (digest [32]byte) { - h := New256() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum384 returns the SHA3-384 digest of the data. -func Sum384(data []byte) (digest [48]byte) { - h := New384() - h.Write(data) - h.Sum(digest[:0]) - return -} - -// Sum512 returns the SHA3-512 digest of the data. -func Sum512(data []byte) (digest [64]byte) { - h := New512() - h.Write(data) - h.Sum(digest[:0]) - return -} diff --git a/crypto/sha3/hashes_generic.go b/crypto/sha3/hashes_generic.go deleted file mode 100644 index f455147..0000000 --- a/crypto/sha3/hashes_generic.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build gccgo appengine !s390x - -package sha3 - -import ( - "hash" -) - -// new224Asm returns an assembly implementation of SHA3-224 if available, -// otherwise it returns nil. -func new224Asm() hash.Hash { return nil } - -// new256Asm returns an assembly implementation of SHA3-256 if available, -// otherwise it returns nil. -func new256Asm() hash.Hash { return nil } - -// new384Asm returns an assembly implementation of SHA3-384 if available, -// otherwise it returns nil. -func new384Asm() hash.Hash { return nil } - -// new512Asm returns an assembly implementation of SHA3-512 if available, -// otherwise it returns nil. -func new512Asm() hash.Hash { return nil } diff --git a/crypto/sha3/keccakf.go b/crypto/sha3/keccakf.go deleted file mode 100644 index 46d03ed..0000000 --- a/crypto/sha3/keccakf.go +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64 appengine gccgo - -package sha3 - -// rc stores the round constants for use in the ι step. -var rc = [24]uint64{ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, -} - -// keccakF1600 applies the Keccak permutation to a 1600b-wide -// state represented as a slice of 25 uint64s. -func keccakF1600(a *[25]uint64) { - // Implementation translated from Keccak-inplace.c - // in the keccak reference code. - var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 - - for i := 0; i < 24; i += 4 { - // Combines the 5 steps in each round into 2 steps. - // Unrolls 4 rounds per loop and spreads some steps across rounds. - - // Round 1 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[6] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[12] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[18] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[24] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] - a[6] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[16] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[22] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[3] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[10] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[1] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[7] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[19] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[20] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[11] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[23] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[4] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[5] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[2] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[8] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[14] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[15] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - // Round 2 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[16] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[7] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[23] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[14] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] - a[16] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[11] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[2] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[18] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[20] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[6] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[22] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[4] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[15] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[1] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[8] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[24] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[10] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[12] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[3] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[19] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[5] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - // Round 3 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[11] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[22] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[8] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[19] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] - a[11] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[1] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[12] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[23] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[15] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[16] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[2] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[24] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[5] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[6] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[3] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[14] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[20] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[7] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[18] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[4] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[10] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - // Round 4 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[1] ^ d1 - bc1 = t<<44 | t>>(64-44) - t = a[2] ^ d2 - bc2 = t<<43 | t>>(64-43) - t = a[3] ^ d3 - bc3 = t<<21 | t>>(64-21) - t = a[4] ^ d4 - bc4 = t<<14 | t>>(64-14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] - a[1] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc2 = t<<3 | t>>(64-3) - t = a[6] ^ d1 - bc3 = t<<45 | t>>(64-45) - t = a[7] ^ d2 - bc4 = t<<61 | t>>(64-61) - t = a[8] ^ d3 - bc0 = t<<28 | t>>(64-28) - t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) - a[5] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc4 = t<<18 | t>>(64-18) - t = a[11] ^ d1 - bc0 = t<<1 | t>>(64-1) - t = a[12] ^ d2 - bc1 = t<<6 | t>>(64-6) - t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) - t = a[14] ^ d4 - bc3 = t<<8 | t>>(64-8) - a[10] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc1 = t<<36 | t>>(64-36) - t = a[16] ^ d1 - bc2 = t<<10 | t>>(64-10) - t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) - t = a[18] ^ d3 - bc4 = t<<56 | t>>(64-56) - t = a[19] ^ d4 - bc0 = t<<27 | t>>(64-27) - a[15] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc3 = t<<41 | t>>(64-41) - t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) - t = a[22] ^ d2 - bc0 = t<<62 | t>>(64-62) - t = a[23] ^ d3 - bc1 = t<<55 | t>>(64-55) - t = a[24] ^ d4 - bc2 = t<<39 | t>>(64-39) - a[20] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - } -} diff --git a/crypto/sha3/keccakf_amd64.go b/crypto/sha3/keccakf_amd64.go deleted file mode 100644 index 7886795..0000000 --- a/crypto/sha3/keccakf_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64,!appengine,!gccgo - -package sha3 - -// This function is implemented in keccakf_amd64.s. - -//go:noescape - -func keccakF1600(a *[25]uint64) diff --git a/crypto/sha3/keccakf_amd64.s b/crypto/sha3/keccakf_amd64.s deleted file mode 100644 index f88533a..0000000 --- a/crypto/sha3/keccakf_amd64.s +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64,!appengine,!gccgo - -// This code was translated into a form compatible with 6a from the public -// domain sources at https://github.com/gvanas/KeccakCodePackage - -// Offsets in state -#define _ba (0*8) -#define _be (1*8) -#define _bi (2*8) -#define _bo (3*8) -#define _bu (4*8) -#define _ga (5*8) -#define _ge (6*8) -#define _gi (7*8) -#define _go (8*8) -#define _gu (9*8) -#define _ka (10*8) -#define _ke (11*8) -#define _ki (12*8) -#define _ko (13*8) -#define _ku (14*8) -#define _ma (15*8) -#define _me (16*8) -#define _mi (17*8) -#define _mo (18*8) -#define _mu (19*8) -#define _sa (20*8) -#define _se (21*8) -#define _si (22*8) -#define _so (23*8) -#define _su (24*8) - -// Temporary registers -#define rT1 AX - -// Round vars -#define rpState DI -#define rpStack SP - -#define rDa BX -#define rDe CX -#define rDi DX -#define rDo R8 -#define rDu R9 - -#define rBa R10 -#define rBe R11 -#define rBi R12 -#define rBo R13 -#define rBu R14 - -#define rCa SI -#define rCe BP -#define rCi rBi -#define rCo rBo -#define rCu R15 - -#define MOVQ_RBI_RCE MOVQ rBi, rCe -#define XORQ_RT1_RCA XORQ rT1, rCa -#define XORQ_RT1_RCE XORQ rT1, rCe -#define XORQ_RBA_RCU XORQ rBa, rCu -#define XORQ_RBE_RCU XORQ rBe, rCu -#define XORQ_RDU_RCU XORQ rDu, rCu -#define XORQ_RDA_RCA XORQ rDa, rCa -#define XORQ_RDE_RCE XORQ rDe, rCe - -#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ - /* Prepare round */ \ - MOVQ rCe, rDa; \ - ROLQ $1, rDa; \ - \ - MOVQ _bi(iState), rCi; \ - XORQ _gi(iState), rDi; \ - XORQ rCu, rDa; \ - XORQ _ki(iState), rCi; \ - XORQ _mi(iState), rDi; \ - XORQ rDi, rCi; \ - \ - MOVQ rCi, rDe; \ - ROLQ $1, rDe; \ - \ - MOVQ _bo(iState), rCo; \ - XORQ _go(iState), rDo; \ - XORQ rCa, rDe; \ - XORQ _ko(iState), rCo; \ - XORQ _mo(iState), rDo; \ - XORQ rDo, rCo; \ - \ - MOVQ rCo, rDi; \ - ROLQ $1, rDi; \ - \ - MOVQ rCu, rDo; \ - XORQ rCe, rDi; \ - ROLQ $1, rDo; \ - \ - MOVQ rCa, rDu; \ - XORQ rCi, rDo; \ - ROLQ $1, rDu; \ - \ - /* Result b */ \ - MOVQ _ba(iState), rBa; \ - MOVQ _ge(iState), rBe; \ - XORQ rCo, rDu; \ - MOVQ _ki(iState), rBi; \ - MOVQ _mo(iState), rBo; \ - MOVQ _su(iState), rBu; \ - XORQ rDe, rBe; \ - ROLQ $44, rBe; \ - XORQ rDi, rBi; \ - XORQ rDa, rBa; \ - ROLQ $43, rBi; \ - \ - MOVQ rBe, rCa; \ - MOVQ rc, rT1; \ - ORQ rBi, rCa; \ - XORQ rBa, rT1; \ - XORQ rT1, rCa; \ - MOVQ rCa, _ba(oState); \ - \ - XORQ rDu, rBu; \ - ROLQ $14, rBu; \ - MOVQ rBa, rCu; \ - ANDQ rBe, rCu; \ - XORQ rBu, rCu; \ - MOVQ rCu, _bu(oState); \ - \ - XORQ rDo, rBo; \ - ROLQ $21, rBo; \ - MOVQ rBo, rT1; \ - ANDQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _bi(oState); \ - \ - NOTQ rBi; \ - ORQ rBa, rBu; \ - ORQ rBo, rBi; \ - XORQ rBo, rBu; \ - XORQ rBe, rBi; \ - MOVQ rBu, _bo(oState); \ - MOVQ rBi, _be(oState); \ - B_RBI_RCE; \ - \ - /* Result g */ \ - MOVQ _gu(iState), rBe; \ - XORQ rDu, rBe; \ - MOVQ _ka(iState), rBi; \ - ROLQ $20, rBe; \ - XORQ rDa, rBi; \ - ROLQ $3, rBi; \ - MOVQ _bo(iState), rBa; \ - MOVQ rBe, rT1; \ - ORQ rBi, rT1; \ - XORQ rDo, rBa; \ - MOVQ _me(iState), rBo; \ - MOVQ _si(iState), rBu; \ - ROLQ $28, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ga(oState); \ - G_RT1_RCA; \ - \ - XORQ rDe, rBo; \ - ROLQ $45, rBo; \ - MOVQ rBi, rT1; \ - ANDQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _ge(oState); \ - G_RT1_RCE; \ - \ - XORQ rDi, rBu; \ - ROLQ $61, rBu; \ - MOVQ rBu, rT1; \ - ORQ rBa, rT1; \ - XORQ rBo, rT1; \ - MOVQ rT1, _go(oState); \ - \ - ANDQ rBe, rBa; \ - XORQ rBu, rBa; \ - MOVQ rBa, _gu(oState); \ - NOTQ rBu; \ - G_RBA_RCU; \ - \ - ORQ rBu, rBo; \ - XORQ rBi, rBo; \ - MOVQ rBo, _gi(oState); \ - \ - /* Result k */ \ - MOVQ _be(iState), rBa; \ - MOVQ _gi(iState), rBe; \ - MOVQ _ko(iState), rBi; \ - MOVQ _mu(iState), rBo; \ - MOVQ _sa(iState), rBu; \ - XORQ rDi, rBe; \ - ROLQ $6, rBe; \ - XORQ rDo, rBi; \ - ROLQ $25, rBi; \ - MOVQ rBe, rT1; \ - ORQ rBi, rT1; \ - XORQ rDe, rBa; \ - ROLQ $1, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ka(oState); \ - K_RT1_RCA; \ - \ - XORQ rDu, rBo; \ - ROLQ $8, rBo; \ - MOVQ rBi, rT1; \ - ANDQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _ke(oState); \ - K_RT1_RCE; \ - \ - XORQ rDa, rBu; \ - ROLQ $18, rBu; \ - NOTQ rBo; \ - MOVQ rBo, rT1; \ - ANDQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _ki(oState); \ - \ - MOVQ rBu, rT1; \ - ORQ rBa, rT1; \ - XORQ rBo, rT1; \ - MOVQ rT1, _ko(oState); \ - \ - ANDQ rBe, rBa; \ - XORQ rBu, rBa; \ - MOVQ rBa, _ku(oState); \ - K_RBA_RCU; \ - \ - /* Result m */ \ - MOVQ _ga(iState), rBe; \ - XORQ rDa, rBe; \ - MOVQ _ke(iState), rBi; \ - ROLQ $36, rBe; \ - XORQ rDe, rBi; \ - MOVQ _bu(iState), rBa; \ - ROLQ $10, rBi; \ - MOVQ rBe, rT1; \ - MOVQ _mi(iState), rBo; \ - ANDQ rBi, rT1; \ - XORQ rDu, rBa; \ - MOVQ _so(iState), rBu; \ - ROLQ $27, rBa; \ - XORQ rBa, rT1; \ - MOVQ rT1, _ma(oState); \ - M_RT1_RCA; \ - \ - XORQ rDi, rBo; \ - ROLQ $15, rBo; \ - MOVQ rBi, rT1; \ - ORQ rBo, rT1; \ - XORQ rBe, rT1; \ - MOVQ rT1, _me(oState); \ - M_RT1_RCE; \ - \ - XORQ rDo, rBu; \ - ROLQ $56, rBu; \ - NOTQ rBo; \ - MOVQ rBo, rT1; \ - ORQ rBu, rT1; \ - XORQ rBi, rT1; \ - MOVQ rT1, _mi(oState); \ - \ - ORQ rBa, rBe; \ - XORQ rBu, rBe; \ - MOVQ rBe, _mu(oState); \ - \ - ANDQ rBa, rBu; \ - XORQ rBo, rBu; \ - MOVQ rBu, _mo(oState); \ - M_RBE_RCU; \ - \ - /* Result s */ \ - MOVQ _bi(iState), rBa; \ - MOVQ _go(iState), rBe; \ - MOVQ _ku(iState), rBi; \ - XORQ rDi, rBa; \ - MOVQ _ma(iState), rBo; \ - ROLQ $62, rBa; \ - XORQ rDo, rBe; \ - MOVQ _se(iState), rBu; \ - ROLQ $55, rBe; \ - \ - XORQ rDu, rBi; \ - MOVQ rBa, rDu; \ - XORQ rDe, rBu; \ - ROLQ $2, rBu; \ - ANDQ rBe, rDu; \ - XORQ rBu, rDu; \ - MOVQ rDu, _su(oState); \ - \ - ROLQ $39, rBi; \ - S_RDU_RCU; \ - NOTQ rBe; \ - XORQ rDa, rBo; \ - MOVQ rBe, rDa; \ - ANDQ rBi, rDa; \ - XORQ rBa, rDa; \ - MOVQ rDa, _sa(oState); \ - S_RDA_RCA; \ - \ - ROLQ $41, rBo; \ - MOVQ rBi, rDe; \ - ORQ rBo, rDe; \ - XORQ rBe, rDe; \ - MOVQ rDe, _se(oState); \ - S_RDE_RCE; \ - \ - MOVQ rBo, rDi; \ - MOVQ rBu, rDo; \ - ANDQ rBu, rDi; \ - ORQ rBa, rDo; \ - XORQ rBi, rDi; \ - XORQ rBo, rDo; \ - MOVQ rDi, _si(oState); \ - MOVQ rDo, _so(oState) \ - -// func keccakF1600(state *[25]uint64) -TEXT ·keccakF1600(SB), 0, $200-8 - MOVQ state+0(FP), rpState - - // Convert the user state into an internal state - NOTQ _be(rpState) - NOTQ _bi(rpState) - NOTQ _go(rpState) - NOTQ _ki(rpState) - NOTQ _mi(rpState) - NOTQ _sa(rpState) - - // Execute the KeccakF permutation - MOVQ _ba(rpState), rCa - MOVQ _be(rpState), rCe - MOVQ _bu(rpState), rCu - - XORQ _ga(rpState), rCa - XORQ _ge(rpState), rCe - XORQ _gu(rpState), rCu - - XORQ _ka(rpState), rCa - XORQ _ke(rpState), rCe - XORQ _ku(rpState), rCu - - XORQ _ma(rpState), rCa - XORQ _me(rpState), rCe - XORQ _mu(rpState), rCu - - XORQ _sa(rpState), rCa - XORQ _se(rpState), rCe - MOVQ _si(rpState), rDi - MOVQ _so(rpState), rDo - XORQ _su(rpState), rCu - - mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) - - // Revert the internal state to the user state - NOTQ _be(rpState) - NOTQ _bi(rpState) - NOTQ _go(rpState) - NOTQ _ki(rpState) - NOTQ _mi(rpState) - NOTQ _sa(rpState) - - RET diff --git a/crypto/sha3/register.go b/crypto/sha3/register.go deleted file mode 100644 index 3cf6a22..0000000 --- a/crypto/sha3/register.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.4 - -package sha3 - -import ( - "crypto" -) - -func init() { - crypto.RegisterHash(crypto.SHA3_224, New224) - crypto.RegisterHash(crypto.SHA3_256, New256) - crypto.RegisterHash(crypto.SHA3_384, New384) - crypto.RegisterHash(crypto.SHA3_512, New512) -} diff --git a/crypto/sha3/sha3.go b/crypto/sha3/sha3.go deleted file mode 100644 index ba269a0..0000000 --- a/crypto/sha3/sha3.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// spongeDirection indicates the direction bytes are flowing through the sponge. -type spongeDirection int - -const ( - // spongeAbsorbing indicates that the sponge is absorbing input. - spongeAbsorbing spongeDirection = iota - // spongeSqueezing indicates that the sponge is being squeezed. - spongeSqueezing -) - -const ( - // maxRate is the maximum size of the internal buffer. SHAKE-256 - // currently needs the largest buffer. - maxRate = 168 -) - -type state struct { - // Generic sponge components. - a [25]uint64 // main state of the hash - buf []byte // points into storage - rate int // the number of bytes of state to use - - // dsbyte contains the "domain separation" bits and the first bit of - // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the - // SHA-3 and SHAKE functions by appending bitstrings to the message. - // Using a little-endian bit-ordering convention, these are "01" for SHA-3 - // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the - // padding rule from section 5.1 is applied to pad the message to a multiple - // of the rate, which involves adding a "1" bit, zero or more "0" bits, and - // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, - // giving 00000110b (0x06) and 00011111b (0x1f). - // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf - // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and - // Extendable-Output Functions (May 2014)" - dsbyte byte - - storage storageBuf - - // Specific to SHA-3 and SHAKE. - outputLen int // the default output size in bytes - state spongeDirection // whether the sponge is absorbing or squeezing -} - -// BlockSize returns the rate of sponge underlying this hash function. -func (d *state) BlockSize() int { return d.rate } - -// Size returns the output size of the hash function in bytes. -func (d *state) Size() int { return d.outputLen } - -// Reset clears the internal state by zeroing the sponge state and -// the byte buffer, and setting Sponge.state to absorbing. -func (d *state) Reset() { - // Zero the permutation's state. - for i := range d.a { - d.a[i] = 0 - } - d.state = spongeAbsorbing - d.buf = d.storage.asBytes()[:0] -} - -func (d *state) clone() *state { - ret := *d - if ret.state == spongeAbsorbing { - ret.buf = ret.storage.asBytes()[:len(ret.buf)] - } else { - ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate] - } - - return &ret -} - -// permute applies the KeccakF-1600 permutation. It handles -// any input-output buffering. -func (d *state) permute() { - switch d.state { - case spongeAbsorbing: - // If we're absorbing, we need to xor the input into the state - // before applying the permutation. - xorIn(d, d.buf) - d.buf = d.storage.asBytes()[:0] - keccakF1600(&d.a) - case spongeSqueezing: - // If we're squeezing, we need to apply the permutatin before - // copying more output. - keccakF1600(&d.a) - d.buf = d.storage.asBytes()[:d.rate] - copyOut(d, d.buf) - } -} - -// pads appends the domain separation bits in dsbyte, applies -// the multi-bitrate 10..1 padding rule, and permutes the state. -func (d *state) padAndPermute(dsbyte byte) { - if d.buf == nil { - d.buf = d.storage.asBytes()[:0] - } - // Pad with this instance's domain-separator bits. We know that there's - // at least one byte of space in d.buf because, if it were full, - // permute would have been called to empty it. dsbyte also contains the - // first one bit for the padding. See the comment in the state struct. - d.buf = append(d.buf, dsbyte) - zerosStart := len(d.buf) - d.buf = d.storage.asBytes()[:d.rate] - for i := zerosStart; i < d.rate; i++ { - d.buf[i] = 0 - } - // This adds the final one bit for the padding. Because of the way that - // bits are numbered from the LSB upwards, the final bit is the MSB of - // the last byte. - d.buf[d.rate-1] ^= 0x80 - // Apply the permutation - d.permute() - d.state = spongeSqueezing - d.buf = d.storage.asBytes()[:d.rate] - copyOut(d, d.buf) -} - -// Write absorbs more data into the hash's state. It produces an error -// if more data is written to the ShakeHash after writing -func (d *state) Write(p []byte) (written int, err error) { - if d.state != spongeAbsorbing { - panic("sha3: write to sponge after read") - } - if d.buf == nil { - d.buf = d.storage.asBytes()[:0] - } - written = len(p) - - for len(p) > 0 { - if len(d.buf) == 0 && len(p) >= d.rate { - // The fast path; absorb a full "rate" bytes of input and apply the permutation. - xorIn(d, p[:d.rate]) - p = p[d.rate:] - keccakF1600(&d.a) - } else { - // The slow path; buffer the input until we can fill the sponge, and then xor it in. - todo := d.rate - len(d.buf) - if todo > len(p) { - todo = len(p) - } - d.buf = append(d.buf, p[:todo]...) - p = p[todo:] - - // If the sponge is full, apply the permutation. - if len(d.buf) == d.rate { - d.permute() - } - } - } - - return -} - -// Read squeezes an arbitrary number of bytes from the sponge. -func (d *state) Read(out []byte) (n int, err error) { - // If we're still absorbing, pad and apply the permutation. - if d.state == spongeAbsorbing { - d.padAndPermute(d.dsbyte) - } - - n = len(out) - - // Now, do the squeezing. - for len(out) > 0 { - n := copy(out, d.buf) - d.buf = d.buf[n:] - out = out[n:] - - // Apply the permutation if we've squeezed the sponge dry. - if len(d.buf) == 0 { - d.permute() - } - } - - return -} - -// Sum applies padding to the hash state and then squeezes out the desired -// number of output bytes. -func (d *state) Sum(in []byte) []byte { - // Make a copy of the original hash so that caller can keep writing - // and summing. - dup := d.clone() - hash := make([]byte, dup.outputLen) - dup.Read(hash) - return append(in, hash...) -} diff --git a/crypto/sha3/sha3_s390x.go b/crypto/sha3/sha3_s390x.go deleted file mode 100644 index 259ff4d..0000000 --- a/crypto/sha3/sha3_s390x.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !gccgo,!appengine - -package sha3 - -// This file contains code for using the 'compute intermediate -// message digest' (KIMD) and 'compute last message digest' (KLMD) -// instructions to compute SHA-3 and SHAKE hashes on IBM Z. - -import ( - "hash" - - "golang.org/x/sys/cpu" -) - -// codes represent 7-bit KIMD/KLMD function codes as defined in -// the Principles of Operation. -type code uint64 - -const ( - // function codes for KIMD/KLMD - sha3_224 code = 32 - sha3_256 = 33 - sha3_384 = 34 - sha3_512 = 35 - shake_128 = 36 - shake_256 = 37 - nopad = 0x100 -) - -// kimd is a wrapper for the 'compute intermediate message digest' instruction. -// src must be a multiple of the rate for the given function code. -//go:noescape -func kimd(function code, chain *[200]byte, src []byte) - -// klmd is a wrapper for the 'compute last message digest' instruction. -// src padding is handled by the instruction. -//go:noescape -func klmd(function code, chain *[200]byte, dst, src []byte) - -type asmState struct { - a [200]byte // 1600 bit state - buf []byte // care must be taken to ensure cap(buf) is a multiple of rate - rate int // equivalent to block size - storage [3072]byte // underlying storage for buf - outputLen int // output length if fixed, 0 if not - function code // KIMD/KLMD function code - state spongeDirection // whether the sponge is absorbing or squeezing -} - -func newAsmState(function code) *asmState { - var s asmState - s.function = function - switch function { - case sha3_224: - s.rate = 144 - s.outputLen = 28 - case sha3_256: - s.rate = 136 - s.outputLen = 32 - case sha3_384: - s.rate = 104 - s.outputLen = 48 - case sha3_512: - s.rate = 72 - s.outputLen = 64 - case shake_128: - s.rate = 168 - case shake_256: - s.rate = 136 - default: - panic("sha3: unrecognized function code") - } - - // limit s.buf size to a multiple of s.rate - s.resetBuf() - return &s -} - -func (s *asmState) clone() *asmState { - c := *s - c.buf = c.storage[:len(s.buf):cap(s.buf)] - return &c -} - -// copyIntoBuf copies b into buf. It will panic if there is not enough space to -// store all of b. -func (s *asmState) copyIntoBuf(b []byte) { - bufLen := len(s.buf) - s.buf = s.buf[:len(s.buf)+len(b)] - copy(s.buf[bufLen:], b) -} - -// resetBuf points buf at storage, sets the length to 0 and sets cap to be a -// multiple of the rate. -func (s *asmState) resetBuf() { - max := (cap(s.storage) / s.rate) * s.rate - s.buf = s.storage[:0:max] -} - -// Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. -func (s *asmState) Write(b []byte) (int, error) { - if s.state != spongeAbsorbing { - panic("sha3: write to sponge after read") - } - length := len(b) - for len(b) > 0 { - if len(s.buf) == 0 && len(b) >= cap(s.buf) { - // Hash the data directly and push any remaining bytes - // into the buffer. - remainder := len(b) % s.rate - kimd(s.function, &s.a, b[:len(b)-remainder]) - if remainder != 0 { - s.copyIntoBuf(b[len(b)-remainder:]) - } - return length, nil - } - - if len(s.buf) == cap(s.buf) { - // flush the buffer - kimd(s.function, &s.a, s.buf) - s.buf = s.buf[:0] - } - - // copy as much as we can into the buffer - n := len(b) - if len(b) > cap(s.buf)-len(s.buf) { - n = cap(s.buf) - len(s.buf) - } - s.copyIntoBuf(b[:n]) - b = b[n:] - } - return length, nil -} - -// Read squeezes an arbitrary number of bytes from the sponge. -func (s *asmState) Read(out []byte) (n int, err error) { - n = len(out) - - // need to pad if we were absorbing - if s.state == spongeAbsorbing { - s.state = spongeSqueezing - - // write hash directly into out if possible - if len(out)%s.rate == 0 { - klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 - s.buf = s.buf[:0] - return - } - - // write hash into buffer - max := cap(s.buf) - if max > len(out) { - max = (len(out)/s.rate)*s.rate + s.rate - } - klmd(s.function, &s.a, s.buf[:max], s.buf) - s.buf = s.buf[:max] - } - - for len(out) > 0 { - // flush the buffer - if len(s.buf) != 0 { - c := copy(out, s.buf) - out = out[c:] - s.buf = s.buf[c:] - continue - } - - // write hash directly into out if possible - if len(out)%s.rate == 0 { - klmd(s.function|nopad, &s.a, out, nil) - return - } - - // write hash into buffer - s.resetBuf() - if cap(s.buf) > len(out) { - s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] - } - klmd(s.function|nopad, &s.a, s.buf, nil) - } - return -} - -// Sum appends the current hash to b and returns the resulting slice. -// It does not change the underlying hash state. -func (s *asmState) Sum(b []byte) []byte { - if s.outputLen == 0 { - panic("sha3: cannot call Sum on SHAKE functions") - } - - // Copy the state to preserve the original. - a := s.a - - // Hash the buffer. Note that we don't clear it because we - // aren't updating the state. - klmd(s.function, &a, nil, s.buf) - return append(b, a[:s.outputLen]...) -} - -// Reset resets the Hash to its initial state. -func (s *asmState) Reset() { - for i := range s.a { - s.a[i] = 0 - } - s.resetBuf() - s.state = spongeAbsorbing -} - -// Size returns the number of bytes Sum will return. -func (s *asmState) Size() int { - return s.outputLen -} - -// BlockSize returns the hash's underlying block size. -// The Write method must be able to accept any amount -// of data, but it may operate more efficiently if all writes -// are a multiple of the block size. -func (s *asmState) BlockSize() int { - return s.rate -} - -// Clone returns a copy of the ShakeHash in its current state. -func (s *asmState) Clone() ShakeHash { - return s.clone() -} - -// new224Asm returns an assembly implementation of SHA3-224 if available, -// otherwise it returns nil. -func new224Asm() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_224) - } - return nil -} - -// new256Asm returns an assembly implementation of SHA3-256 if available, -// otherwise it returns nil. -func new256Asm() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_256) - } - return nil -} - -// new384Asm returns an assembly implementation of SHA3-384 if available, -// otherwise it returns nil. -func new384Asm() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_384) - } - return nil -} - -// new512Asm returns an assembly implementation of SHA3-512 if available, -// otherwise it returns nil. -func new512Asm() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_512) - } - return nil -} - -// newShake128Asm returns an assembly implementation of SHAKE-128 if available, -// otherwise it returns nil. -func newShake128Asm() ShakeHash { - if cpu.S390X.HasSHA3 { - return newAsmState(shake_128) - } - return nil -} - -// newShake256Asm returns an assembly implementation of SHAKE-256 if available, -// otherwise it returns nil. -func newShake256Asm() ShakeHash { - if cpu.S390X.HasSHA3 { - return newAsmState(shake_256) - } - return nil -} diff --git a/crypto/sha3/sha3_s390x.s b/crypto/sha3/sha3_s390x.s deleted file mode 100644 index 8a4458f..0000000 --- a/crypto/sha3/sha3_s390x.s +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !gccgo,!appengine - -#include "textflag.h" - -// func kimd(function code, chain *[200]byte, src []byte) -TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 - MOVD function+0(FP), R0 - MOVD chain+8(FP), R1 - LMG src+16(FP), R2, R3 // R2=base, R3=len - -continue: - WORD $0xB93E0002 // KIMD --, R2 - BVS continue // continue if interrupted - MOVD $0, R0 // reset R0 for pre-go1.8 compilers - RET - -// func klmd(function code, chain *[200]byte, dst, src []byte) -TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 - // TODO: SHAKE support - MOVD function+0(FP), R0 - MOVD chain+8(FP), R1 - LMG dst+16(FP), R2, R3 // R2=base, R3=len - LMG src+40(FP), R4, R5 // R4=base, R5=len - -continue: - WORD $0xB93F0024 // KLMD R2, R4 - BVS continue // continue if interrupted - MOVD $0, R0 // reset R0 for pre-go1.8 compilers - RET diff --git a/crypto/sha3/sha3_test.go b/crypto/sha3/sha3_test.go deleted file mode 100644 index 005a242..0000000 --- a/crypto/sha3/sha3_test.go +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// Tests include all the ShortMsgKATs provided by the Keccak team at -// https://github.com/gvanas/KeccakCodePackage -// -// They only include the zero-bit case of the bitwise testvectors -// published by NIST in the draft of FIPS-202. - -import ( - "bytes" - "compress/flate" - "encoding/hex" - "encoding/json" - "fmt" - "hash" - "os" - "strings" - "testing" -) - -const ( - testString = "brekeccakkeccak koax koax" - katFilename = "testdata/keccakKats.json.deflate" -) - -// testDigests contains functions returning hash.Hash instances -// with output-length equal to the KAT length for SHA-3, Keccak -// and SHAKE instances. -var testDigests = map[string]func() hash.Hash{ - "SHA3-224": New224, - "SHA3-256": New256, - "SHA3-384": New384, - "SHA3-512": New512, - "Keccak-256": NewLegacyKeccak256, - "Keccak-512": NewLegacyKeccak512, -} - -// testShakes contains functions that return sha3.ShakeHash instances for -// with output-length equal to the KAT length. -var testShakes = map[string]struct { - constructor func(N []byte, S []byte) ShakeHash - defAlgoName string - defCustomStr string -}{ - // NewCShake without customization produces same result as SHAKE - "SHAKE128": {NewCShake128, "", ""}, - "SHAKE256": {NewCShake256, "", ""}, - "cSHAKE128": {NewCShake128, "CSHAKE128", "CustomStrign"}, - "cSHAKE256": {NewCShake256, "CSHAKE256", "CustomStrign"}, -} - -// decodeHex converts a hex-encoded string into a raw byte string. -func decodeHex(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} - -// structs used to marshal JSON test-cases. -type KeccakKats struct { - Kats map[string][]struct { - Digest string `json:"digest"` - Length int64 `json:"length"` - Message string `json:"message"` - - // Defined only for cSHAKE - N string `json:"N"` - S string `json:"S"` - } -} - -func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) { - xorInOrig, copyOutOrig := xorIn, copyOut - xorIn, copyOut = xorInGeneric, copyOutGeneric - testf("generic") - if xorImplementationUnaligned != "generic" { - xorIn, copyOut = xorInUnaligned, copyOutUnaligned - testf("unaligned") - } - xorIn, copyOut = xorInOrig, copyOutOrig -} - -// TestKeccakKats tests the SHA-3 and Shake implementations against all the -// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage -// (The testvectors are stored in keccakKats.json.deflate due to their length.) -func TestKeccakKats(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - // Read the KATs. - deflated, err := os.Open(katFilename) - if err != nil { - t.Errorf("error opening %s: %s", katFilename, err) - } - file := flate.NewReader(deflated) - dec := json.NewDecoder(file) - var katSet KeccakKats - err = dec.Decode(&katSet) - if err != nil { - t.Errorf("error decoding KATs: %s", err) - } - - for algo, function := range testDigests { - d := function() - for _, kat := range katSet.Kats[algo] { - d.Reset() - in, err := hex.DecodeString(kat.Message) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - d.Write(in[:kat.Length/8]) - got := strings.ToUpper(hex.EncodeToString(d.Sum(nil))) - if got != kat.Digest { - t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s", - algo, impl, kat.Length, kat.Message, got, kat.Digest) - t.Logf("wanted %+v", kat) - t.FailNow() - } - continue - } - } - - for algo, v := range testShakes { - for _, kat := range katSet.Kats[algo] { - N, err := hex.DecodeString(kat.N) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - - S, err := hex.DecodeString(kat.S) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - d := v.constructor(N, S) - in, err := hex.DecodeString(kat.Message) - if err != nil { - t.Errorf("error decoding KAT: %s", err) - } - - d.Write(in[:kat.Length/8]) - out := make([]byte, len(kat.Digest)/2) - d.Read(out) - got := strings.ToUpper(hex.EncodeToString(out)) - if got != kat.Digest { - t.Errorf("function=%s, implementation=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n %s\nwanted:\n %s", - algo, impl, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest) - t.Logf("wanted %+v", kat) - t.FailNow() - } - continue - } - } - }) -} - -// TestKeccak does a basic test of the non-standardized Keccak hash functions. -func TestKeccak(t *testing.T) { - tests := []struct { - fn func() hash.Hash - data []byte - want string - }{ - { - NewLegacyKeccak256, - []byte("abc"), - "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", - }, - { - NewLegacyKeccak512, - []byte("abc"), - "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", - }, - } - - for _, u := range tests { - h := u.fn() - h.Write(u.data) - got := h.Sum(nil) - want := decodeHex(u.want) - if !bytes.Equal(got, want) { - t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want) - } - } -} - -// TestUnalignedWrite tests that writing data in an arbitrary pattern with -// small input buffers. -func TestUnalignedWrite(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - buf := sequentialBytes(0x10000) - for alg, df := range testDigests { - d := df() - d.Reset() - d.Write(buf) - want := d.Sum(nil) - d.Reset() - for i := 0; i < len(buf); { - // Cycle through offsets which make a 137 byte sequence. - // Because 137 is prime this sequence should exercise all corner cases. - offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1} - for _, j := range offsets { - if v := len(buf) - i; v < j { - j = v - } - d.Write(buf[i : i+j]) - i += j - } - } - got := d.Sum(nil) - if !bytes.Equal(got, want) { - t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) - } - } - - // Same for SHAKE - for alg, df := range testShakes { - want := make([]byte, 16) - got := make([]byte, 16) - d := df.constructor([]byte(df.defAlgoName), []byte(df.defCustomStr)) - - d.Reset() - d.Write(buf) - d.Read(want) - d.Reset() - for i := 0; i < len(buf); { - // Cycle through offsets which make a 137 byte sequence. - // Because 137 is prime this sequence should exercise all corner cases. - offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1} - for _, j := range offsets { - if v := len(buf) - i; v < j { - j = v - } - d.Write(buf[i : i+j]) - i += j - } - } - d.Read(got) - if !bytes.Equal(got, want) { - t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) - } - } - }) -} - -// TestAppend checks that appending works when reallocation is necessary. -func TestAppend(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - d := New224() - - for capacity := 2; capacity <= 66; capacity += 64 { - // The first time around the loop, Sum will have to reallocate. - // The second time, it will not. - buf := make([]byte, 2, capacity) - d.Reset() - d.Write([]byte{0xcc}) - buf = d.Sum(buf) - expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" - if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { - t.Errorf("got %s, want %s", got, expected) - } - } - }) -} - -// TestAppendNoRealloc tests that appending works when no reallocation is necessary. -func TestAppendNoRealloc(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - buf := make([]byte, 1, 200) - d := New224() - d.Write([]byte{0xcc}) - buf = d.Sum(buf) - expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" - if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { - t.Errorf("%s: got %s, want %s", impl, got, expected) - } - }) -} - -// TestSqueezing checks that squeezing the full output a single time produces -// the same output as repeatedly squeezing the instance. -func TestSqueezing(t *testing.T) { - testUnalignedAndGeneric(t, func(impl string) { - for algo, v := range testShakes { - d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr)) - d0.Write([]byte(testString)) - ref := make([]byte, 32) - d0.Read(ref) - - d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr)) - d1.Write([]byte(testString)) - var multiple []byte - for range ref { - one := make([]byte, 1) - d1.Read(one) - multiple = append(multiple, one...) - } - if !bytes.Equal(ref, multiple) { - t.Errorf("%s (%s): squeezing %d bytes one at a time failed", algo, impl, len(ref)) - } - } - }) -} - -// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing. -func sequentialBytes(size int) []byte { - result := make([]byte, size) - for i := range result { - result[i] = byte(i) - } - return result -} - -func TestReset(t *testing.T) { - out1 := make([]byte, 32) - out2 := make([]byte, 32) - - for _, v := range testShakes { - // Calculate hash for the first time - c := v.constructor(nil, []byte{0x99, 0x98}) - c.Write(sequentialBytes(0x100)) - c.Read(out1) - - // Calculate hash again - c.Reset() - c.Write(sequentialBytes(0x100)) - c.Read(out2) - - if !bytes.Equal(out1, out2) { - t.Error("\nExpected:\n", out1, "\ngot:\n", out2) - } - } -} - -func TestClone(t *testing.T) { - out1 := make([]byte, 16) - out2 := make([]byte, 16) - - // Test for sizes smaller and larger than block size. - for _, size := range []int{0x1, 0x100} { - in := sequentialBytes(size) - for _, v := range testShakes { - h1 := v.constructor(nil, []byte{0x01}) - h1.Write([]byte{0x01}) - - h2 := h1.Clone() - - h1.Write(in) - h1.Read(out1) - - h2.Write(in) - h2.Read(out2) - - if !bytes.Equal(out1, out2) { - t.Error("\nExpected:\n", hex.EncodeToString(out1), "\ngot:\n", hex.EncodeToString(out2)) - } - } - } -} - -// BenchmarkPermutationFunction measures the speed of the permutation function -// with no input data. -func BenchmarkPermutationFunction(b *testing.B) { - b.SetBytes(int64(200)) - var lanes [25]uint64 - for i := 0; i < b.N; i++ { - keccakF1600(&lanes) - } -} - -// benchmarkHash tests the speed to hash num buffers of buflen each. -func benchmarkHash(b *testing.B, h hash.Hash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - b.SetBytes(int64(size * num)) - b.StartTimer() - - var state []byte - for i := 0; i < b.N; i++ { - for j := 0; j < num; j++ { - h.Write(data) - } - state = h.Sum(state[:0]) - } - b.StopTimer() - h.Reset() -} - -// benchmarkShake is specialized to the Shake instances, which don't -// require a copy on reading output. -func benchmarkShake(b *testing.B, h ShakeHash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - d := make([]byte, 32) - - b.SetBytes(int64(size * num)) - b.StartTimer() - - for i := 0; i < b.N; i++ { - h.Reset() - for j := 0; j < num; j++ { - h.Write(data) - } - h.Read(d) - } -} - -func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) } -func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) } -func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) } -func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) } - -func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) } -func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) } -func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } -func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } - -func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } - -func Example_sum() { - buf := []byte("some data to hash") - // A hash needs to be 64 bytes long to have 256-bit collision resistance. - h := make([]byte, 64) - // Compute a 64-byte hash of buf and put it in h. - ShakeSum256(h, buf) - fmt.Printf("%x\n", h) - // Output: 0f65fe41fc353e52c55667bb9e2b27bfcc8476f2c413e9437d272ee3194a4e3146d05ec04a25d16b8f577c19b82d16b1424c3e022e783d2b4da98de3658d363d -} - -func Example_mac() { - k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long") - buf := []byte("and this is some data to authenticate") - // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key. - h := make([]byte, 32) - d := NewShake256() - // Write the key into the hash. - d.Write(k) - // Now write the data. - d.Write(buf) - // Read 32 bytes of output from the hash into h. - d.Read(h) - fmt.Printf("%x\n", h) - // Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff -} - -func ExampleNewCShake256() { - out := make([]byte, 32) - msg := []byte("The quick brown fox jumps over the lazy dog") - - // Example 1: Simple cshake - c1 := NewCShake256([]byte("NAME"), []byte("Partition1")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 2: Different customization string produces different digest - c1 = NewCShake256([]byte("NAME"), []byte("Partition2")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 3: Longer output length produces longer digest - out = make([]byte, 64) - c1 = NewCShake256([]byte("NAME"), []byte("Partition1")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 4: Next read produces different result - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Output: - //a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b - //a8db03e71f3e4da5c4eee9d28333cdd355f51cef3c567e59be5beb4ecdbb28f0 - //a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8 - //85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109 -} diff --git a/crypto/sha3/shake.go b/crypto/sha3/shake.go deleted file mode 100644 index d7be295..0000000 --- a/crypto/sha3/shake.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This file defines the ShakeHash interface, and provides -// functions for creating SHAKE and cSHAKE instances, as well as utility -// functions for hashing bytes to arbitrary-length output. -// -// -// SHAKE implementation is based on FIPS PUB 202 [1] -// cSHAKE implementations is based on NIST SP 800-185 [2] -// -// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf -// [2] https://doi.org/10.6028/NIST.SP.800-185 - -import ( - "encoding/binary" - "io" -) - -// ShakeHash defines the interface to hash functions that -// support arbitrary-length output. -type ShakeHash interface { - // Write absorbs more data into the hash's state. It panics if input is - // written to it after output has been read from it. - io.Writer - - // Read reads more output from the hash; reading affects the hash's - // state. (ShakeHash.Read is thus very different from Hash.Sum) - // It never returns an error. - io.Reader - - // Clone returns a copy of the ShakeHash in its current state. - Clone() ShakeHash - - // Reset resets the ShakeHash to its initial state. - Reset() -} - -// cSHAKE specific context -type cshakeState struct { - *state // SHA-3 state context and Read/Write operations - - // initBlock is the cSHAKE specific initialization set of bytes. It is initialized - // by newCShake function and stores concatenation of N followed by S, encoded - // by the method specified in 3.3 of [1]. - // It is stored here in order for Reset() to be able to put context into - // initial state. - initBlock []byte -} - -// Consts for configuring initial SHA-3 state -const ( - dsbyteShake = 0x1f - dsbyteCShake = 0x04 - rate128 = 168 - rate256 = 136 -) - -func bytepad(input []byte, w int) []byte { - // leftEncode always returns max 9 bytes - buf := make([]byte, 0, 9+len(input)+w) - buf = append(buf, leftEncode(uint64(w))...) - buf = append(buf, input...) - padlen := w - (len(buf) % w) - return append(buf, make([]byte, padlen)...) -} - -func leftEncode(value uint64) []byte { - var b [9]byte - binary.BigEndian.PutUint64(b[1:], value) - // Trim all but last leading zero bytes - i := byte(1) - for i < 8 && b[i] == 0 { - i++ - } - // Prepend number of encoded bytes - b[i-1] = 9 - i - return b[i-1:] -} - -func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash { - c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}} - - // leftEncode returns max 9 bytes - c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) - c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) - c.initBlock = append(c.initBlock, N...) - c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) - c.initBlock = append(c.initBlock, S...) - c.Write(bytepad(c.initBlock, c.rate)) - return &c -} - -// Reset resets the hash to initial state. -func (c *cshakeState) Reset() { - c.state.Reset() - c.Write(bytepad(c.initBlock, c.rate)) -} - -// Clone returns copy of a cSHAKE context within its current state. -func (c *cshakeState) Clone() ShakeHash { - b := make([]byte, len(c.initBlock)) - copy(b, c.initBlock) - return &cshakeState{state: c.clone(), initBlock: b} -} - -// Clone returns copy of SHAKE context within its current state. -func (c *state) Clone() ShakeHash { - return c.clone() -} - -// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. -// Its generic security strength is 128 bits against all attacks if at -// least 32 bytes of its output are used. -func NewShake128() ShakeHash { - if h := newShake128Asm(); h != nil { - return h - } - return &state{rate: rate128, dsbyte: dsbyteShake} -} - -// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. -// Its generic security strength is 256 bits against all attacks if -// at least 64 bytes of its output are used. -func NewShake256() ShakeHash { - if h := newShake256Asm(); h != nil { - return h - } - return &state{rate: rate256, dsbyte: dsbyteShake} -} - -// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, -// a customizable variant of SHAKE128. -// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is -// desired. S is a customization byte string used for domain separation - two cSHAKE -// computations on same input with different S yield unrelated outputs. -// When N and S are both empty, this is equivalent to NewShake128. -func NewCShake128(N, S []byte) ShakeHash { - if len(N) == 0 && len(S) == 0 { - return NewShake128() - } - return newCShake(N, S, rate128, dsbyteCShake) -} - -// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, -// a customizable variant of SHAKE256. -// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is -// desired. S is a customization byte string used for domain separation - two cSHAKE -// computations on same input with different S yield unrelated outputs. -// When N and S are both empty, this is equivalent to NewShake256. -func NewCShake256(N, S []byte) ShakeHash { - if len(N) == 0 && len(S) == 0 { - return NewShake256() - } - return newCShake(N, S, rate256, dsbyteCShake) -} - -// ShakeSum128 writes an arbitrary-length digest of data into hash. -func ShakeSum128(hash, data []byte) { - h := NewShake128() - h.Write(data) - h.Read(hash) -} - -// ShakeSum256 writes an arbitrary-length digest of data into hash. -func ShakeSum256(hash, data []byte) { - h := NewShake256() - h.Write(data) - h.Read(hash) -} diff --git a/crypto/sha3/shake_generic.go b/crypto/sha3/shake_generic.go deleted file mode 100644 index add4e73..0000000 --- a/crypto/sha3/shake_generic.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build gccgo appengine !s390x - -package sha3 - -// newShake128Asm returns an assembly implementation of SHAKE-128 if available, -// otherwise it returns nil. -func newShake128Asm() ShakeHash { - return nil -} - -// newShake256Asm returns an assembly implementation of SHAKE-256 if available, -// otherwise it returns nil. -func newShake256Asm() ShakeHash { - return nil -} diff --git a/crypto/sha3/testdata/keccakKats.json.deflate b/crypto/sha3/testdata/keccakKats.json.deflate deleted file mode 100644 index 7a94c2f8bce62c70664cda859a30845cab713c24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 540828 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

r46_VrdCQ_>b^q8k=CXV-{AK%%}5RO9u(dzXPu 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 z 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

FTjCk4EfUM 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%0DqQa){X-aj;KFxu|u-~Y19U#!gK<<*(t+rgptqG^ z7(@G0G?`oZY8lGDY;j!&_ zDwOxx1Rff*WCR;F+!>!NTC^$xg%_7voU`XxYqUz}$+^{c&!c|+BJ*)BkfZ*2>dofP zv}VC8X{G*(6|UcFkm=3q3J=10cE}Yt_pKQpd$14A&Zlf3YM>u!kL=&lOgj`iT^}zP*n@);zceJ zDzVSY5#5f}+;q5b>Kb02>8lED~$Vj#3Y^b zJI-Qa+l^w)_Pb`dccPp08*yiciV)Gv(=p>_r|!cCGdfRwMXd0ytdu_5v-Yb+% zK64Z_yWQYC>e}||;_1vTs@S|*C1>;OVA$Ct{)AD&o4sp@Rj-Bj{frAB*6Qxp8Y|cZ zvUMP$7&RykGAA`&sFTBI>0!J)sc>V@ZGS{b_pHG5F{Jv`<`{*UY$sbHnu}+8<<5@! zCG)zTw*6M%{2%AgXXv~8g;Gm)?GfF*XHO0^@+Wt>dm`Uc=8}ESYqqN;R67Vo%{bqvBH@<<0aZjAFmnGKA7nz$L;HFuQO@_DX4y?4FC&bbD#Hh}kdmg)xgqd*o zbTIAQ6W^)UT$ZZGzEHAbaF`RKX{hbIt-3%+nx*Yrm-a}<=Qq6lS%I$##GF^pXP_T8 z1I2b%d_ zhG{^a{z}l{9Jsj*gJ;2Nsy`5VL?4}(zH4%Nto&7khwB0!S@zM-Mk)#DeGp^yxOG!=N?Mkivlk*wI9CfSK&wu4O)-Ckj?Yx%S#ZrJl`k=SopemjlMKn;r*8Qnhy=v|F@EIw zeuBkdvH*jvT`9(}W)?kShml;fL5ddIt&7Ck?j4E;YQyJtbZvuKd48sH;hVpc1}iHq zrTaj15}tws-Z)yl2OlqGIWCvy1zZ*De%JERZi)Mr3i7kG3L>b?>Bn63CF6n?pi4}| zQfGF;iq5siYhCN0Duqt#@gNc>2((YWK=IL)f{+66Nu+9c@qR1U!9Z%!5gNCIdp<$z zJ7*SY{Q*9(26+UCi79?VT#3wd5Fe6H`1*YM)UWT9)l&iFnx|)k%v}49(>^!O0r?y! zMVE%ZO90H{e#6d7GiMC?AQBw%pgLJL<*WzB>rw1*D7tjo>K@U@r$|k-Y1_XmMivpp z4lDDwijP^Etu_zPd9@JYyC4ED*5>fv3Gk;68&?GRt@V}hsm%XwOnHwlJ=ziLS3iS` zOq%1AX45RSe))4{e9x*89){uNnj?mG?V3bC;8P;>DjykKo5GKI9Ju^wOvrsqs5ad@ zA5+y+*?AG*tTWN88032TMr;Zu1AdZ=cW)XhS7XC>hGr%dP5~+RCF=`~Bb;9FSltEp zHIZxfIGT37eeOU}Ut44K$O)MBPG5f{y3qF;6TD=`%gt36X-~r7`%6`h?5?oI8u-a$ zn;haf6gQOW%8`6Y0tbhDFz+6yNy_(tN1U%&%>8;5!TyvtqVwlLdn1xNk5AA)o%*;a< zFmOrigrgggLYncm-V?WOM94*d_*cfo=z&VQ^x#JA;DR0Xj*UDwJp!&+#5T%f3Vr)D z$eF#MxmiyFMnQJ$ERGil^eB@ z8y%+fNL-IQ33tfFVWsXXAorXXsB@#guDfIQUNuOikBU6Z0FHI6=`Dv2--kD@*8~~s zp;uO<$fH`PMH{K#F1)eoo^TS*gFQf;lN+&o_5Oh35-zqLC zo|o9$GM48veZQ|lWSY+QRt1fJUCb5DH_=|9xV?i6QDa4(_+Y^}IwCY}4l%w0I=C|I zt0uOlGI(N{*Alvt9(%0uJueoe8364?+SfR{iK3qZ)xqn=%gaN*D|kw|Mpx%3ZBVV< zb592w$z#~(2Ht6$0h}Qel7^$4whn0mj}(8DE01nAOO)b{iSoHnP<;e3zIg^m)W`2L zg%C*Aw9)TL<5#|GIa*s{tL*W=^Lf!|l%<7s==uDwD(4Q|0bo{CJALhu_D29DoaIwO zfaB@PU%z4UD!{kHgSg2DjGSv3piTclr!{CTM^Xc+lEaTdW z(z^$@USeE$OCOoI2rqTpHy=f6k2F#BmN8v8!*y03h^X0bQj=Pe&w_d9|T}-FOZtBI_r>#8+NH`i9A88y*L*3tuxR1KecGJh^2*wZZN<4=wZ6`A)pO z51&tJ@RZ9jy$dWG&3XG%i|wuc2F+p_yc6ZI(xqcA4_Z}SUzb-igpUB!X^wmByw?cG z1(V4B^gP)t--oJpvIhy!O;wJZf2QgwZGORq`sr+sm;*kxU#&26Y=W|qgD9QxjL|B+ zItMR{awuW04H4Z(9ySND755xmLt^jdYpsPs2d;aX8IpX&bdmUzS3GM|b?~!aW6fB} z$LcS*QDp9lL?6TY?g73*JYvq?jE%6HO4ZI}R&D$C(SXb&Prk>7DdQ5{w^Oap7PFp% zWV$1J`ViQwwr&;S+w`@q?Sn*HCw!D4f5&Cv=YghAD+7GAPZiT$Prc`sQuZTCJ^QAJl^EwG&PUYVMBOOPm3J&sl4B5%YLfNXlE~v zE#CKFu3osQy7-EUBEp_P7#(S9v^JBANz}Sf*I;dw2t%Px9@4w|9xYy!`#!OU(@lv} zeZulpGlYJx9}scV-ny37Br9!Ue$owgMB8qB-67(=Tj9rS9)NK?fBO3o{5?}B^^IuF zXB2OE?nFx+)_~yr6hth4OR^lU| zLpFML^L`MxV<2(kP~9x-$XLp~8P%)8?=f8>*%qV2S6Fd&{rX*w6scn;#2UYA?@JLF za8us4YwMDVsEUmFw6OFfwZq$=0x@$^KBokf+wWz1A59&V;cTbar1<=Fr_I$Yzkxz( zS#Vb|s@>^_YE>ZAaPAcBuMrT}fMGso8;3x+B|lQ!+Iv#UF3BTFh+lSc`9k>M zxg~q?_)C(EN(PwZqarsRLr(hSlOo|9!O04GkeTQ-%q#hrO9Ke0a`fx=pET^b=d+OB zU6U%bS9n649|0_pubrV#J(o|-%Quxym1TV5-U~c5wZdn&P@&^*T#bMG075ZZt?G4C z(xXjn4}ZF?mMVz%oMZ*FUc5K4%YyU5^n0d+4&A6n_jTv8A_asmXWDy*&*gxP(7 zT5cv^hfAyHY*TbMJNqE>z1k5+vP>@9#%Jo*o1A4Yo!mCMbu8i~Dta_rR`@~lF@{ge z+TpR?E1Debx9!^!0X;9x`>lSp^i!Go=UDi61L=C)zIfF0U^FsQ{pm9u-pXz&dx5NcgKPfl^a8ogg94K+wWihivRM@MMSjT_!E z?>keeeQo%JU*EtvS0+gwS+D%OfEW95>jqN!4%Iw91?MA32dlg@+%C#12Z$UZYK{8< zz>%pDfy<8v{x_fgcD_H}O?0LYjm>qKF1R%Q5Q+PqzOV*c-?;FSJ>Xt&!*5_Gg1xNR zLQ9E*gd`ZEJ2%`yjdLI2V>r=aNMlwUo$Y2mi^ke~NttNqf}A@FuinKA_j<2U_bo@f zC3AilYA#&$M1sP73GG}-QX%bX9=3X% zpxoH#JRX$yGrg;qc{qYU_2~!9d$+xv=PEm!Q#_Yu%6jz6-)U#hz`3S2O;Rg@f+R{7{sj*pPk9vxljI?36nBR~;`={ytd9CpWakE?$9yXd6QJ&B|-%oSvNH}!-N9f`}rmxF8z!%PYGRY z%YCpkd*Kr*IdS=8zV-g-o;9l?1sFJ#3?w0v9;b){moJ9yxK-^BpOaIGTzewj^`qU!Ex%i&=V=7^2rY3 zDWjLhw?4xU`XK&g%uoICvjqoH#~AGIrcVem6}0}DuxA7Pda`%fUPdjoxkd?(GnCHP zyRUIxly3WOy1KUF!tJ#I_e2K?$uQj3a3DQbOlS0H$(kDRdvsI5-_Zm#_dKXkMK=>d zNQs)d&-=C_f*ON>!@D%=E4P3e8*0A^i8+_`t~Y$$+K~+`$}~$5RAeJUbKz@g2-M6# zX?&GNeOdLbEBJ|F{=zd>hHmwyDLt5IRpLj*u4K%)q5Tc-zDXb zmBc*OxJ(&cZ>aD7m-K@29iA6G>#*JSDGHRCATk9`KM_#n zcr*P?XG_r;5YgB(=h)!zx%Y9QfXxLe*E^L6xLa2r4Lin)l&p+LN#CH4&ntH0I(&OfYGH_Ting6abMYT6W@V(3WCVK z&}j$}`tn)yOC~)%jMtCLIoDkdAR@J(#nY9k%k-h6z>;#esQMSz5R+e1|7UX{E;u9y zJ_p_Enw7RJdFrf=3XIyV{6dKDLDtDRciWj^UTK!^pGN+LW>h1+g`ield5!1R1rj}< zIl<^-7y|`D_cq@--=)2M18ygxpx#2d8dWJ5N3Ax07VP``fbnr&GsSCpY`3fJ{14aSX$?M`rHS z)ibT<(Sp4~LiFuVtshqLq!BalTVj}iPZjeFoQL;$>6Dpp>{`lq^^Cnz`k;5Hk88c+ zU>j0TI<5d6_g8N|H|?up_@1rh>5~=abMTO#)>p*dV#$Va#Hsh1*R`B+>~^EYtb<3! zQyS?&iMF{#l&V10?t2VcAG^7Uq~v)bL_jVbT#S50}_8zk?J14u~X19$85Zf?=(wR9KCN9 z&eqr5L7vtfML~G+^Du9J0Bg9G$`A*Ifys6HP4`zU$82qI@7ypDv=#{!eFCQMh!u@% zTrIMDH$lW7(p{087Hky9NTS1I3j96t8}_7V5wnE%xlZbBII<`Es@8W2xV~N`UV^i? zSsXqTz1%1cmI40Or&J(?+|bGi7KNB04kOF0)k05_>W-nF(3^T17nqAC>YGaa>R!MP`j`L>NH`x0TQm*A<1qPR7nSA4r zj^2`{SG9UME`#3s`f?K?!LMD=5NZ2NNB?=9~p&V8EURfoLtO1xw!b~1B%6;M5YuCcAxVWDP$QOkoSarEdzbf+zaOGYUjO!UWs0|tQPi${0hc}V`Jti z`t;Z<3&nQS+TqqE^w0loud6OpeV6Bk&ypstxqA82_vKjDFtBww0Is903(9w$Ko+&* z@MFNs{9RtIYv-2ly;qP4(Q;dLKS2cCX@AzmF#;8)$FlrJ@jGN0U){LvuooyB~C zzI5!3PPW`t0us<_z!W)@qa^v1H$_;9*!o#=3tNtmTzfCwflWv^f)*C^z_dW&2CQ_A zy}9xpDD?Ow&^{cD>=7tVvNL-DW$P8=D7<`)IxIaI`XK}zs6JeBMgw9Z~>=2 zz{8@cR)oV_q=Kh$K<_yb$=neWqc-n*Phu~M?OY&7Qwj9EN2q9z5^nOBTq~qsXZ0mB zK2$!!y$`?NLu4HCL=&ZnSLwiIicxw1>~0nxA^CHcEMp3BK)F*^GP(%RdXk+sVnmS& z0xY$nP^fjai%BK<1eTUuAa=#G;S|mg8fQV5L=v`|OZ};{LDHwrNm9Rj==bUlY+CKy z(}AX+(H3pycRKRwC3KuPo3Ma|NmtB6k@KucxZu^1y=JcS*}UHNlU2T8J+a4pHtfbe z4bq|4;4x>zVf80H_bYun%{S~{L2Gx z3=+&;fd@@biIj-i$@k}7WdW~mhig}X#9IgR^+^ZX^_0(>MThy7pP=LbDEI>wv{5+0wBmIzO{%8%86-ABCy)YSOPVxy9K zp>u{9)0@1{DJKA>FNhfLzR4;sPmt+KI6lq{#j5$J)ydC6qS*+t$?DKO(#O|Rrd$?@ zKQnqgE@zJwEQPD;h4&(>yhd=vc|Cm9HHZQ?@oETW3Gux?cOREuyy%vlhjCODA42=j z>*iN}9zW6?CWbcc_nx^dzR=TGW@_iCKdD5eVJm5wxe)TDW6Vap%7yY4V>UY-``lpS znh=9l>m?|$2!iQ-pq`?%-l{Lb`VsVwtnc0G>Z6kk5&=WC3y zzD?ND`h;}p>Qmp%;99S=WIaSxJbX_ND8(aqxcZiCo^-ac~!(N&2lOik)k*L@tR1<1PXjg@+`%vUjvh)jmq~f3V8>O7I1;9D= z+l`Aa6}5YgBA=8km4}uOUry$rWzWaF}@o+vi zJCNC5Tre%1e1b!xXuvOW>fGk$_~MT1X%i8n&o5LFQ<7*Ix%Y9H1HyWzDNd5PzacvI z_z)k#Q_=#|Uo05rY4c?rgU2@3LJwl@ty`y;Y}fN#{jy@f?wlt-t-NmRd5hU0q7brA zCy&@fD9I5xkIWzc;-paq32ndY-KKYB@jlFf&}KTF#XWu#TCj*qmZk5QfBsTAAc6Oh z6Xi=!JJ7i;+HV0IoX_9+jAZ%sJCDc@kphpX#d=8By_qa}u8cIi<>64PQeVqn+#RL-{8frq?3Q2;Q_+0;z#iA`nX_;5*~Q~m9jLtX>y=&Qibhvu zPK7(-#}|3>aZQA8lUmQ8^Jk-KL}F%{r27|S%I}4QrPcf2rFzep)f~4F2D`_fHq~LO z#T)qMt?w%~>QN5;*S6y^kaX{pu5aSeN{7tyD|@pl+vH*MhQ_}{N8Hk=%lzfkxD^0F z>08EXeWv?F9vr$(zYDkGZ+~iQ`AqY)k{NR@_=Twf0H39V$Cg0rTs~s5ClD3T5e=Z( zvPMHl>L}`W08kIW&Q79cI>g1Nu^@?`d}ElzRL(OE~#+%E(8eUIS;CGB~c(=O)=ia{>=N^CFu!h zoLCoPpo^PCmCJLx4nE?ZQXBzm_=u|9AOn;Xa_spanY8IUTEY8RiiW-V0@r$L>U4$M z`w8D=0d{+%_?{8bXCR)$Rt8A-2M)!nsGKbfJ$m6$#fxW7C=z_)g)#PC8$5pe{jsg( zzQx;SmM-#iAm^8Pg2c4*6z;i5p%1{2UKv>-tOOrN6qc>WX9pNIBd>c?g2}z~xZazi z>qb?gTlc9U)aY~5<{VseQ$2hcE9vsR^^SCnonGEY&@zZo<`Ox`}gnAB@LSSUTjdP8}`13lu28@=fkF=h#K+0G3 zEv+TKKxw?EDaT3m2z(d1M4cKS_;44xKX~8Lr;IC(o=d00y=r71LheByjN)41ywC~+ z#MO9=Go7Ri0kC7OvQR_AhxsPRaS?+1-DrR~H{)}ULTP`i6*U!s3lzWoGw6ix(wk3w z4M+p;<-K3M(BtRJm0SI1xb3o6NM!N3y$=jyJ^ffPF;|Rm^s6#l1|~8+N7(Q3x!Tiw zJ>QS(ye~0v)65pavVW3$_H!xx{M*0FGH>ZVPzuV6`0ez-c)T~TV1;?!Y&A9&B0FWi z7eS#j}ne7<=R$&we=m+<1)%Bk}3_&zhiWqZ`ufX|~c(Ye)%S_u7M zySEE()#os=yGGSx>zCN0xQ|_HBICTrCpPx6GN7aDe!*7>Cu5aEw@Po^h13RmBLiw> zp~`t?l-W;xF=8{Qd}n4tyL^)j7kQZ*2+*mSrg6Q!JEroU^ZD0p9#=X-o}@#863dof zcn*UZ?7qdGQR$ag`(AbYi4fOQx-adgfJzZP6Z zG~257gl)%VINfS?W1{*q;U_x807ZS{m51FD51fdZuHVJ`=iy{sxevn{m5ZUP-6&su zIB@>L9y!kFDFaevJRA`>y?NB%1h z3YA~r_TymV1IaLY**Eg@1TV=Sp>V_kMUSa^z`;sZ6Q`DU*^Mhbx8(q z#+wqK*%(1hu}(&xhNKf;kl!)CGblp=_n+A@R@9A^Sddl?r;r)q6as-I#YKaNHMm!= z-L8J`Ke_PBOQZv+I0Eu@>d9$P``Qv=PXJ5MfJv;kUSm0@<@Tw^wHVTm<6{8^2Lg#4 zfT-*6kYX%+5xV8c;omNNHNKxM&+j_5y!?JI|=n0me&$B1#;9@9?%W8EHo z<=X5momaI)->OT9>$0>_ifTSOjMG}VBw3nvWg&0BihUmW(zrP)afB^Cmp8&?y4#29 zisT*xszU(mv{p<{Y!V1zM;3e?@ZzmwTHSJ9T}pZ7A4+TiqQAHmhUCY0gOobv5ZXD# z9h*5_fpkW%y!UXj9(5-Q_U37M0!8&pjsHw@6Cg^b_yOv7sf=FFiskJ&$5>(f~TJqzSA`f_=@F9v+f}zMgp|=2s*Ly*Z6u?2HYkEx! zC&g*Zjs@DOWa|S1>*u`X*1rG3v}%dpWP^prd+O_4gk;w>xw(sUHEpUZ_r^R`bo_8|@T6NbouB2~e;!kQ zT-P!!l$CG?742|{#VLO}luq8$(`DCbR2cbHrbA6slkI~izWAR`lq0SZ_StgmJ!g3( zOIE)tJ5ixlh3XKpp5|{zqP*1e2=C$@5m9A2uPU=*4!528j$FQ+`tyoCy^4XXx#=-e z5_>QfZP>J;;5|T~Kd|#?G1yypA5hX1$?{_zO**HklWY!6C%zg8d*QC^ny$gtLygDj zb`hV>D@)1KO5aI`U1+>n$_bJNP0-&T6u!6lK&;eN<1wUf4>teV90($dM(6BI<7tpr zN@iK4XX>okSi5)lN(|935T4D|IuA^rLW44{R|3XBijC+!w&3Shxb&uWC~}kL3Egu& z31&v77wgK*tGs)XPjh4z_(Xd=?taW(S(q<(sMn+j?khT9fAsFB-CRQ_iLX!k=>4KL z^YBAx&eDCH^N|jlC_W_XIuDk0z|Xq2);VqS?R|jDDTotbjiLPc{fc^-f~gnYxY4k$ zEbfyY0_ZBA!P18xi|v-iuf9#$#m|$dN>dG~ZHaJ~Bem{rUlV-DNB6z95FtmO3Cyc+ z!rDFv;#UIRnpW?-s__PqHY+TQvAJ>}!F#ozmmgaG*EG_1SZy8TKx05FSaj%F&>ZlYM7MEQv+Vd<5Rv53J#W% zf;(<(jVoQ8b6K5Rs}UCu@zb%(*^IV9d`{Ar#E7q2A52?B&t$)2fO7buM&qgN06(cD z9RYc)eN@Mz-R?b$Ko?~$athS4Gm#Q@a7PVMm{>i^SQnURR)Bk z#9U-#nsbjvE384C+PPjzFelM;_OH7KnImS;1uKyi#OjlB?e5eO<$VwuTSeF3f4Y+Q zigo0&{=D4I@bkb@5{~JCdu2&%^y1l*1yygcx7V>tb|uT&KO^H@ZExAiYq>?aMoH55 z*4=Qr1o2&OK3`xbN$5JR$wTNcczmwc;MidxyKUTthj0(lx8aL1U)UjF0KEZ;%@&@D zx3*lho4WMwwUp5~xy@C#>jA)R#&OK2x!A7Fb+m+uCx5TX4pjk-2}a!By;q^X?%|&I z;|CTQT(0TV7Ga>GKIYF)Hlrd(&y|yhn9ZE|h8anDEmO9>M^(~hK6Yo~MAAMf+2AU5 z?Vmj-T^PgyMe@dVTG;VIl_x5v9--wjOEe?j(E9{u0CS?e$!9(1DIQ|*FY@xd@#XaC zcwCfczh23n-R(E8LYPe2;~`P^NS^4k3aU6&rl;;@^uC8mfLhyfv9`MuU#X>Zv0J@Y z{1K@+VYW^l?hkKc=1M*|%vYkh?ic%UX%ZyPTkzsAJ!{)|)^8t~y4n|ySP`TJ6^7|2 zmKYHL?vp$!-~MU0NZ0_obo!;J#tgf7LmTK6M*|_2ABylir*54AkE+MO?%58k*^Qzl z%YO7PX+#?U$NF-6fuBax;D^nr5Nrqi@vkepXWaS%B4D8om~}7+9ey-sZfF?_*`y%( z)kn+^=aaK897=DFf8agK_$7th^_v=-@ZHPF(h?W^!iNflb&%*4r-DQX#hGtg>*$m{ zewsJFh_8i}d}PO~`s?4_D#aDtIB@y%N>VzSJ=Y&bk8j(9`yoWQWLlZrC?NNs-fNAE z3Rp>6RPhND^U`!6`ABy zhoVgiw|o?j=V6!8{UWAyx61cv zXbp-Fu?q#G=Z$TM9xL@ne#?Glp7Z&Abm>et@annQ4}`SLf;tWuPKVZaFYXqBx8~PF zUDeLv7S6Z3?%c{e?Yp>nz#rl7{hm0d64 zc$}OV5Ug%J)7#ru?&qfEBi_eCL$|dC1`o(WSwiGqJv>-(ZPxel?Kf=YA}qp`iVF6G z&f096JP_s2nTRbZfu9mNdkQ#{s7McbOO>7P5c+TDIAP3C!w7cxaxH6vGaI~erj1lj zpHIA%!v+0a%KgsGFp2)z@6F9$sE;Z-@{$&}+EJOq^bm?^Q#jvubNP+vqpglJ_u!&k zjhd4j_X&u@42J*|}@f;fjZY9>qLW3W(q;%o%;qI_{B5ObpzE*&NHw9~mZjvyK5+JPpF^z?xs5H3R$sWcJa)h-au!YY;B~*K2}yk)qqeVW7K9nU z)eIC^JynQsY30Kv#x7i!X14?43TyJfjsJ-iQEr&T&t=kZcnwCM03ptUpV_WMa1b5kc-qd| zUNuy%*&$jrc(^;LE{aFV&H|3;gRHN&^?W8PXaj}Ou7{LXRul#A)&qwVzQ#vkzb(ap z%ti*{qP!>MDEAe0w|p4GEBi$*GTGJjTCrIg{O%EDx!)cnz%=yYnGl6h<^gnx1lJ2-z_G6=B^}tLV0fVfV?;1V& zME2$CJtFB$lF+ytT5F2@^;KYhk=G)8T~aQMeJQlER$s}fi=D#P&S!?{nM+S>%^v!k z6|tk9h7^jT$Ma9b0A=Ted>mCx9)GTfPrfsH^pT?S&sy(DD9XqQnj86$NAEH5xMRD> zw~4qu%acd^DmmW^d_+0@ykG4Z+=u->pw8OQaRt9!KDa=i&)63Pz3yGapNe@Z0PxWw ze^dmv3>o2QPA$ker(-5cfwO9n$H2{c8>d9CEv#z4{!#7=1sZk z4PBWA@oD|zd}rYLxToJc_xxR5yI=aVsfh^0;Uhu0a#g)o@n##sWxV`UTN|1KU1F@XQQ#k=yD0*iH6zH>u0`8w^)+{ zhB(eredH1)U_E^vNXS^UK8H`-BY9m2S@TP)BU{PaT)yYPnjT>+eF7~szt3M)ve=-= z`E+5`amn}^UZ2=F5XT`OJr#4Od|%x1?=X$=h$>yS2lbdR^yRVC!9!|0k#|)7=_81J zts;PEpWLih9`Q@R`ikSSyt}9(DAnq}%n%<`Qn?;KPOF z+u7IeBZ7FRzTBnz#dq~h4Y#oDfmhn@NMd%5=FCW3ew4!eYdkqD2OLuA>8RTTSYCNr zXK2(KQmaF@57xdFVd*%;`xN&aksG{sm1kIW?~X9E-mI(hrLfy$V=RCm z>0L+%%ACG9o>yd-+bJr4UYck6egD#&{fU{37}M)$c8KJ{mjpBDi8`Vq%DgD0!aAbN6zGA|xVhVOzezyrUr)t1qiAGbMTai415 z8tlLaPpzS&bu^L}H_yzQq(0)N2gilto=96TB$!iU4|3i z^{DP-85FX6b-V?9D^meNd6N*u8`;79)q&V*PCtpwCh40yi|OAzT0!viZNf~EO%f@I$ror>JBR7 zf%#Hj`H=?$IGkDMj-ojRN#A}eA+B|Hw^bg)f4f$lC)T32(j> zeFBuVJ2u!(y^k#Uv_Dd2U8)1uvcI6iuR*TNM~aU76nzoi_c7nBDGqKVi9|bx=FX*N z^q#jS_8hA`ufil?hT_S%Pd4v9{w-t(=h^@Sh83jktv7XZ5b9i+n~Z+rA(R*P>V)9> zd1}0QXA;g-7sy@obK;6*9l)C>b`C6ct6j>TG%+Od@b7Zo{GGW;naAi@h?%39-8FnF z?V47iIG6C#@Cs9CGEdAujdHIuT-O{Tuu~PVeQsQ5i@Ectnp_-;@4j33weRG+X6UBW zp(QxAv1WLH>wJMH>dB*XQK-JTMTgXQTKR}h>=z42=9+!^-j^%W-S7%z-WkxTl4>E%39Ovf7f33sj` zh!FaEEpCN>(dG0d=frUh`f`f*%2Q-9*P2g#77ukfIs2{;=YaIpQhyp)MjsqlKM09i zH^hswa?;P;bTWD>E8HX=6DbP+HmsPirjtK6hJe`|-bb?!eOZQj?ew9WstE9frk%o5 zmqNE-7UAj5xR-1n>=fGh`0g&Z+%Y@Y_mDnlKahA0o6tO}e*1Ux{dvS$iJxEP<xrn*LvW8#+^gDjNcfi0sf6%Y@`|#s zxhZB8tKUJMeuihq3*Sq4n5?LHS3z*DDqj$Bm1LujSy|;hpSjw70-{u?E)#4Db|J=S zQauTl?Bo|$&b=M#@f~AUGwtIADRe7R)TdG3iZlw^2O}yJ&|p+|;!aXp9dj2QafR=k z4kc)@FZGG{Q5&V@2nn)wp37lAGn-aq@uj#g2tm5%-Hml}egd|i>>0JtwfanP?ar0= zweqi>mQ;b3`;=1R*p-bpmx$3y_mvj4^3T-^9&tsr%e*0TQgeDQ(^QK=n1_|>rlLOZ ziDISTskf}~*m8Fy!Tr2O1&?1oSM&zs;=&{zKG{yvyUC(r+cp9-~5Bs{jvJa$RQ$g6ur7wTA{KNZtBV^cFH=Wu7xzxQKdeM z1>9U>0g!78D%>lLOap%AKju6|3c9u#9&KIYwyeK#LP)`Flh$v$DB{~u-{YN z2@bnjji0qNKD~YgWUDfKdKv=r^R=6SFY`5@=7@r?$9vusoVUJG>QT>7huEsGrL(oZ zEn1&kwrVIgUxe&wXs*cpl0Yr|tn<>~sAl9DgM} zml@d*>$=*TX2a)wJHgHSJ*&~Jd^p&2&~L}Eex_C|U&a@U*ph+^;qiWqaTspfI4OP? za8mpBsjt86bG?0{_kV<4O_KDu3cQl|hb0KO|B)u-nq^0PtM|T%?yj;ek(m}`%HScZ zL{>Y>-`PLlj+S&py~V+Sm&%2P9d5=YEE+w~1XoXM$&=#9r=Et~-upIoUQHcYcPRXF z*68U3SN&3JrRx9(~o2tC7r8=6J2}EyzAnrlq7*ilBgI|QqQOx zSZ3C=9EOe=W>J8t?&}h^om6=QSrEPLiazRcNBRjQNff2G98qGKmiT-Vo1x!iF_TAq z1MRGkDuCbd(YopwO`{fE7M=sVap0}DcQuB<-yAqzHtj|q2EmybkEIi!@ako}?LDJF zW%$LXht_v_k>rQf$uNqKI`&AP1GcH=;4K0y8a)q?fAKI8xRnYaNIS5Io^$6T> zioWb=Pb8ZHFoz@6(LLR)=O%PVoSeE#dozr%&-ea7PCSlvnGK^C9W95C$TtwnI!$fT zmrA3%NcHd6Ec*BC=I5hYS0Y_L!wVg(9NQ5K|Ax@fMzYXk#i)sR?aNChIA4F8&;ixs zv)HYpQOGr?41j7iO~0i6xC57cW5D$Q-hI!y`D1g^D^*S)PhJyx?GjJ9o{e`m2s) z-{1+61ff@??$@wBucj^nqQCO7e7eOhBcFb}z{==r8kw`nb_npa-M68_a2kn5dR`$( zL_NRqOmCC8{;Qy0o6MZIPEO`yw}=vW(ihQv=AIGv$eKE#8BTD_u>+nUz2)~L!`JIM z=koE8Gm{}b{;3(am2ovcTLBn!m zm0PD(`B3PD;}hbjmu%Gs;^x!CkwcFL(suybbhLfv`eE!2;B#n0kK&i01y5*b+_~qL zH#yry?<2<#&Xmx79N62=+yGTTs=tF_aUkrR0mrhpw-tK*OQ*b`uii|Z2Y7nrXF2W< z3AhLuspjZ!1aQ7gXUj#Vui5&<@a)>-S0X70$FIm+qAhuBnW$)rn<<)U(t^+95C9KK zGV;r2M;~xUSn~4VReS)2e2x>YUw`1$XD2@g|G^Sb{(|mh3GyP~*d@O=R6VX?^2)+_T^FAH78n-|-c%*rz-;Lnl#IWn8*9b*di_RmCI^bt~p2}8dc|8um)`DVcd{?0f{<=~Rrllnn9 zoG$sk_h%Ax84qfY7zPxz3nv7u2zgLZ^VfjKb^OxPCND8bn9)cTUB3!_<%Tnt^rThx zlYFkyQ>Q`}X;aYVi(jT&@#FO7{D?{N$h)__4WEx3hyW17Jd)cuZX1s~-TP$u`@tLr zWivLc!{4wV0J!yI{+qE@SQ~k}@D=WnW49OhZm)nf-jb~t&iZ#rUlDQ1#=FW0HgXe* zAg1!1%X5v(>dQT7c-x41ywo>+GC?2JCFcA>sb+3GEmi8U?fIlL>xqcRa*#bPtAW6z z+y_h#tt&!eo4LWDg-$l7nC8>d1^g;nAUIfo+7{E1)3*3@!1_GqD4>wv_?<~amY==C z`Z!=$-@|W1zxtadLH$_$T#qrj9Qc;fwT2RO&|X37)+@%z6=z z-N>2X)XZI8Sc(jYSF*P+S>1FnI>afwEhM#v@MBbAf_#?FL1yiQ27r4$WBuYkN@Nbd=YyXEBb+w*V!P$BntD8Q7I|>L=z%!Rd-aGPsW^08 zAYNgT!-O3f!NR4Uv*$*ib_janu&sgb>AUOS4Ws7%UdAF}J!LXDOGJ!#){5di>@2($ zgKRTA?&r^vZhszyZntGHeLd^>Da)jkAr>3ao?7#9F3a<_z!|^VLe=MD=MWUyIadMw zv3I6$sG&ljS3eWLTjJViDF>zN(^&~hasgf9ZbdfO=g?;LBwfk{|4ipJ?{yso#m~W$ zfhQ6UXL{ffN_?M!@TpR%yzQIo-+JpuE0KgJ3g-@TZNp z`f-O;^K3xRRaZke_JrDAqboO!4@=-@wHH|EFhO;vOrd%V5iaFtdp|Pwvs=F1H`96U zA{o-X=kXhntLXo1RCGaFfU#L93bbxjDn^@0A8DTx5Ccrmo+) zOLyy$ZbYS7-_IobzF(sc(6UJu=H?U*pGBOG<=dyBVheV^_|kbAlw-k3hfwlSW*BDX z0LsY8yQD`gZFKUX;7Ws$FBjtqxa7WdGc)Mqo0E!%4&lE0OpWMD_nNa#K$~KpAh}rROB2-T&6CO;Qo{};nV6v$#gDi$4K4V zVxL(F+@X{t=r10i9}3!M?FUEqn$4>by%5QIkV^WSVfa$p1TQPGiD?|Q?{#is!Z(t; z7_EFx!%5?zm z@Yuu2XBYT9_0Xg_*2w8YW|@2{Ys=+eor(hNjbgl*5ssM{8kRWyzA-U7@JMt#$?;Gn zA65xM6_+{Ox+Md0h=g}EQI25>Ug1Xe0a{0)y|3br^TV5qv>Jka9wYRIRj!$jU4mm3(qXP


;$zL+MxI{G7r<YyJ|ZNOj7 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

%y|=lM+9bx#X7Na5GWAL^|x9M}^ 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 diff --git a/crypto/sha3/xor.go b/crypto/sha3/xor.go deleted file mode 100644 index 079b650..0000000 --- a/crypto/sha3/xor.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64,!386,!ppc64le appengine - -package sha3 - -// A storageBuf is an aligned array of maxRate bytes. -type storageBuf [maxRate]byte - -func (b *storageBuf) asBytes() *[maxRate]byte { - return (*[maxRate]byte)(b) -} - -var ( - xorIn = xorInGeneric - copyOut = copyOutGeneric - xorInUnaligned = xorInGeneric - copyOutUnaligned = copyOutGeneric -) - -const xorImplementationUnaligned = "generic" diff --git a/crypto/sha3/xor_generic.go b/crypto/sha3/xor_generic.go deleted file mode 100644 index fd35f02..0000000 --- a/crypto/sha3/xor_generic.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -import "encoding/binary" - -// xorInGeneric xors the bytes in buf into the state; it -// makes no non-portable assumptions about memory layout -// or alignment. -func xorInGeneric(d *state, buf []byte) { - n := len(buf) / 8 - - for i := 0; i < n; i++ { - a := binary.LittleEndian.Uint64(buf) - d.a[i] ^= a - buf = buf[8:] - } -} - -// copyOutGeneric copies ulint64s to a byte buffer. -func copyOutGeneric(d *state, b []byte) { - for i := 0; len(b) >= 8; i++ { - binary.LittleEndian.PutUint64(b, d.a[i]) - b = b[8:] - } -} diff --git a/crypto/sha3/xor_unaligned.go b/crypto/sha3/xor_unaligned.go deleted file mode 100644 index a3d0686..0000000 --- a/crypto/sha3/xor_unaligned.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64 386 ppc64le -// +build !appengine - -package sha3 - -import "unsafe" - -// A storageBuf is an aligned array of maxRate bytes. -type storageBuf [maxRate / 8]uint64 - -func (b *storageBuf) asBytes() *[maxRate]byte { - return (*[maxRate]byte)(unsafe.Pointer(b)) -} - -func xorInUnaligned(d *state, buf []byte) { - n := len(buf) - bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8] - if n >= 72 { - d.a[0] ^= bw[0] - d.a[1] ^= bw[1] - d.a[2] ^= bw[2] - d.a[3] ^= bw[3] - d.a[4] ^= bw[4] - d.a[5] ^= bw[5] - d.a[6] ^= bw[6] - d.a[7] ^= bw[7] - d.a[8] ^= bw[8] - } - if n >= 104 { - d.a[9] ^= bw[9] - d.a[10] ^= bw[10] - d.a[11] ^= bw[11] - d.a[12] ^= bw[12] - } - if n >= 136 { - d.a[13] ^= bw[13] - d.a[14] ^= bw[14] - d.a[15] ^= bw[15] - d.a[16] ^= bw[16] - } - if n >= 144 { - d.a[17] ^= bw[17] - } - if n >= 168 { - d.a[18] ^= bw[18] - d.a[19] ^= bw[19] - d.a[20] ^= bw[20] - } -} - -func copyOutUnaligned(d *state, buf []byte) { - ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) - copy(buf, ab[:]) -} - -var ( - xorIn = xorInUnaligned - copyOut = copyOutUnaligned -) - -const xorImplementationUnaligned = "unaligned" diff --git a/p2p/chain_sync.go b/p2p/chain_sync.go index f1b9f36..5c02424 100644 --- a/p2p/chain_sync.go +++ b/p2p/chain_sync.go @@ -16,7 +16,7 @@ package p2p -import "fmt" +//import "fmt" //import "net" import "time" @@ -71,7 +71,7 @@ try_again: request.TopoHeights = append(request.TopoHeights, 0) fill_common(&request.Common) // fill common info if err := connection.RConn.Client.Call("Peer.Chain", request, &response); err != nil { - fmt.Printf("Call failed Peer.Chain : %v \n", err) + rlog.Debugf("Call failed Peer.Chain : %v \n", err) return } // we have a response, see if its valid and try to add to get the blocks @@ -117,7 +117,7 @@ try_again: orequest.Block_list = append(orequest.Block_list, response.Block_list[i]) fill_common(&orequest.Common) if err := connection.RConn.Client.Call("Peer.GetObject", orequest, &oresponse); err != nil { - fmt.Printf("Call faileda Peer.GetObject: %v\n", err) + rlog.Debugf("Call faileda Peer.GetObject: %v\n", err) return } else { // process the response if err = connection.process_object_response(oresponse); err != nil { diff --git a/walletapi/daemon_communication.go b/walletapi/daemon_communication.go index ff9c2ad..3e75fcc 100644 --- a/walletapi/daemon_communication.go +++ b/walletapi/daemon_communication.go @@ -158,11 +158,13 @@ func (w *Wallet_Memory) Sync_Wallet_Memory_With_Daemon() { previous := w.account.Balance_Result.Data var scid crypto.Hash if _, _, err := w.GetEncryptedBalanceAtTopoHeight(scid, -1, w.GetAddress().String()); err == nil { - if w.account.Balance_Result.Data != previous || (len(w.account.EntriesNative[scid]) >= 1 && strings.ToLower(w.account.Balance_Result.Data) != strings.ToLower(w.account.EntriesNative[scid][len(w.account.EntriesNative[scid])-1].EWData)) { + if w.account.Balance_Result.Data != previous /*|| (len(w.account.EntriesNative[scid]) >= 1 && strings.ToLower(w.account.Balance_Result.Data) != strings.ToLower(w.account.EntriesNative[scid][len(w.account.EntriesNative[scid])-1].EWData)) */ { w.DecodeEncryptedBalance() // try to decode balance w.SyncHistory(scid) // also update statement w.save_if_disk() // save wallet + } else { + w.save_if_disk() // save wallet } } else { rlog.Infof("getbalance err %s", err) @@ -267,6 +269,24 @@ func (w *Wallet_Memory) GetEncryptedBalanceAtTopoHeight(scid crypto.Hash, topohe if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(errormsg.ErrAccountUnregistered.Error())) && accountaddr == w.GetAddress().String() && scid.IsZero() { w.Error = errormsg.ErrAccountUnregistered } + + //fmt.Printf("will return errr now \n") + + // all SCID users are considered registered and their balance is assumed zero + + if !scid.IsZero() { + if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(errormsg.ErrAccountUnregistered.Error())) { + if addr, err1 := rpc.NewAddress(accountaddr); err1 != nil { + err = err1 + return + } else { + e = crypto.ConstructElGamal(addr.PublicKey.G1(), crypto.ElGamal_BASE_G) // init zero balance + bits = 128 + err = nil + return + } + } + } return }