DERO-HE STARGATE Testnet Release13
This commit is contained in:
parent
650b57b4cf
commit
fd2a2eba7f
@ -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 <url>.
|
||||
|
||||
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.
|
||||
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
@ -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 <url>.
|
||||
|
||||
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.
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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/
|
@ -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.
|
@ -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)
|
@ -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.
|
@ -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
|
||||
}
|
@ -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})
|
||||
}
|
||||
}
|
@ -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}
|
||||
|
||||
// <sage>
|
||||
// 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}
|
||||
|
||||
// <sage>
|
||||
// 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}
|
||||
|
||||
// <sage>
|
||||
// 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}}
|
@ -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
|
||||
}
|
||||
}
|
@ -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) }
|
@ -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
|
||||
}
|
@ -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<len(bin); i++ {}`
|
||||
for i := range bin {
|
||||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above
|
||||
if bin[i] != 0 {
|
||||
return errors.New("invalid infinity encoding")
|
||||
}
|
||||
}
|
||||
e.p.SetInfinity()
|
||||
//panic("point is infinity")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decompress the point P (P =/= ∞)
|
||||
var err error
|
||||
if err = e.p.x.Unmarshal(bin[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// MontEncode our field elements for fast finite field arithmetic
|
||||
// Needs to be done since the z and t coordinates are also encoded (ie: created with newGFp)
|
||||
montEncode(&e.p.x, &e.p.x)
|
||||
y, err := getYFromMontEncodedX(&e.p.x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.p.y = *y
|
||||
|
||||
// The flag serializationBigY is set (so the point pt with the higher Y is encoded)
|
||||
// but the point e retrieved from the `getYFromX` is NOT the higher, then we inverse
|
||||
if !e.IsHigherY() {
|
||||
if encoding[0]&serializationBigY != 0 {
|
||||
e.Neg(e)
|
||||
}
|
||||
} else {
|
||||
if encoding[0]&serializationBigY == 0 { // The point given by getYFromX is the higher but the mask is not set for higher y
|
||||
e.Neg(e)
|
||||
}
|
||||
}
|
||||
|
||||
// No need to check that the point e.p is on the curve
|
||||
// since we retrieved y from x by using the curve equation.
|
||||
// Adding it would be redundant
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 *G1) DecodeUncompressed(encoding []byte) error {
|
||||
if len(encoding) != G1UncompressedSize {
|
||||
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 = &curvePoint{}
|
||||
} else {
|
||||
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
|
||||
// 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, G1UncompressedSize)
|
||||
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
|
||||
}
|
||||
|
||||
// Decode the point P (P =/= ∞)
|
||||
var err error
|
||||
// Decode the x-coordinate
|
||||
if err = e.p.x.Unmarshal(bin[1:33]); err != nil {
|
||||
return err
|
||||
}
|
||||
// Decode the y-coordinate
|
||||
if err = e.p.y.Unmarshal(bin[33:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// MontEncode our field elements for fast finite field arithmetic
|
||||
montEncode(&e.p.x, &e.p.x)
|
||||
montEncode(&e.p.y, &e.p.y)
|
||||
|
||||
if !e.p.IsOnCurve() {
|
||||
return errors.New("malformed point: Not on the curve")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
func (e *G1) DecodeUncompressed(encoding []byte) error {
|
||||
if len(encoding) != G1UncompressedSize {
|
||||
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 = &curvePoint{}
|
||||
}
|
||||
|
||||
// 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, G1UncompressedSize)
|
||||
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 remote the flags and unmarshall the data
|
||||
_, err := e.Unmarshal(encoding[1:])
|
||||
return err
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func assertGFpEqual(t *testing.T, a, b *gfP) {
|
||||
for i := 0; i < FpUint64Size; i++ {
|
||||
assert.Equal(t, a[i], b[i], fmt.Sprintf("The %d's elements differ between the 2 field elements", i))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeCompressed(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 EncodeCompress function
|
||||
GaCopy1 := new(G1)
|
||||
GaCopy1.Set(GaInit)
|
||||
compressed := GaCopy1.EncodeCompressed()
|
||||
|
||||
// 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,
|
||||
compressed[1:], // Ignore the masking byte
|
||||
marshalled[:32], // Get only the x-coordinate
|
||||
"The EncodeCompressed and Marshal function yield different results for the x-coordinate")
|
||||
|
||||
// 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 decodeCompress function
|
||||
Gb2 := new(G1)
|
||||
err = Gb2.DecodeCompressed(compressed)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, GaAffine.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, GaAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed 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 EncodeCompress function
|
||||
GInfinityCopy1 := new(G1)
|
||||
GInfinityCopy1.Set(GInfinity)
|
||||
compressed = GInfinityCopy1.EncodeCompressed()
|
||||
|
||||
// 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,
|
||||
compressed[1:], // Ignore the masking byte
|
||||
marshalled[:32],
|
||||
"The EncodeCompressed 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.DecodeCompressed(compressed)
|
||||
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")
|
||||
}
|
||||
|
||||
func TestIsHigherY(t *testing.T) {
|
||||
_, Ga, err := RandomG1(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
Ga.p.MakeAffine()
|
||||
GaYString := Ga.p.y.String()
|
||||
GaYBig := new(big.Int)
|
||||
_, ok := GaYBig.SetString(GaYString, 16)
|
||||
assert.True(t, ok, "ok should be True")
|
||||
|
||||
GaNeg := new(G1)
|
||||
GaNeg.Neg(Ga)
|
||||
GaNeg.p.MakeAffine()
|
||||
GaNegYString := GaNeg.p.y.String()
|
||||
GaNegYBig := new(big.Int)
|
||||
_, ok = GaNegYBig.SetString(GaNegYString, 16)
|
||||
assert.True(t, ok, "ok should be True")
|
||||
|
||||
// Verify that Ga.p.y + GaNeg.p.y == 0
|
||||
sumYs := &gfP{}
|
||||
fieldZero := newGFp(0)
|
||||
gfpAdd(sumYs, &Ga.p.y, &GaNeg.p.y)
|
||||
assert.Equal(t, *sumYs, *fieldZero, "The y-coordinates of P and -P should add up to zero")
|
||||
|
||||
// Find which point between Ga and GaNeg is the one witht eh higher Y
|
||||
res := gfpCmp(&GaNeg.p.y, &Ga.p.y)
|
||||
if res > 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")
|
||||
}
|
@ -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<len(bin); i++ {}`
|
||||
for i := range bin {
|
||||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above
|
||||
if bin[i] != 0 {
|
||||
return errors.New("invalid infinity encoding")
|
||||
}
|
||||
}
|
||||
e.p.SetInfinity()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decompress the point P (P =/= ∞)
|
||||
var err error
|
||||
if err = e.p.x.x.Unmarshal(bin[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = e.p.x.y.Unmarshal(bin[FqElementSize+1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// MontEncode our field elements for fast finite field arithmetic
|
||||
// Needs to be done since the z and t coordinates are also encoded (ie: created with newGFp)
|
||||
montEncode(&e.p.x.x, &e.p.x.x)
|
||||
montEncode(&e.p.x.y, &e.p.x.y)
|
||||
|
||||
y, err := getYFromMontEncodedXG2(&e.p.x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.p.y = *y
|
||||
|
||||
// The flag serializationBigY is set (so the point pt with the higher Y is encoded)
|
||||
// but the point e retrieved from the `getYFromX` is NOT the higher, then we inverse
|
||||
if !e.IsHigherY() {
|
||||
if encoding[0]&serializationBigY != 0 {
|
||||
e.Neg(e)
|
||||
}
|
||||
} else {
|
||||
if encoding[0]&serializationBigY == 0 { // The point given by getYFromX is the higher but the mask is not set for higher y
|
||||
e.Neg(e)
|
||||
}
|
||||
}
|
||||
|
||||
// No need to check that the point e.p is on the curve
|
||||
// since we retrieved y from x by using the curve equation.
|
||||
// Adding it would be redundant
|
||||
return nil
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestG2DecodeCompressed(t *testing.T) {
|
||||
_, GaInit, err := RandomG2(rand.Reader)
|
||||
assert.NoError(t, err, "Err should be nil")
|
||||
|
||||
// Affine form of GaInit
|
||||
GaAffine := new(G2)
|
||||
GaAffine.Set(GaInit)
|
||||
GaAffine.p.MakeAffine()
|
||||
|
||||
// Encode GaCopy1 with the EncodeCompress function
|
||||
GaCopy1 := new(G2)
|
||||
GaCopy1.Set(GaInit)
|
||||
compressed := GaCopy1.EncodeCompressed()
|
||||
|
||||
// Encode GaCopy2 with the Marshal function
|
||||
GaCopy2 := new(G2)
|
||||
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,
|
||||
compressed[1:], // Ignore the masking byte
|
||||
marshalled[:64], // Get only the x-coordinate
|
||||
"The EncodeCompressed and Marshal function yield different results for the x-coordinate",
|
||||
)
|
||||
|
||||
// Unmarshal the point Ga with the unmarshal function
|
||||
Gb1 := new(G2)
|
||||
_, 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 decodeCompress function
|
||||
Gb2 := new(G2)
|
||||
err = Gb2.DecodeCompressed(compressed)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, GaAffine.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, GaAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed point should equal the y-coord of the intial point")
|
||||
|
||||
// == Case2: Encode the point at infinity == //
|
||||
GInfinity := new(G2)
|
||||
GInfinity.p = &twistPoint{}
|
||||
GInfinity.p.SetInfinity()
|
||||
|
||||
// Get the point in affine form
|
||||
GInfinityAffine := new(G2)
|
||||
GInfinityAffine.Set(GInfinity)
|
||||
GInfinityAffine.p.MakeAffine()
|
||||
|
||||
// Encode GaCopy1 with the EncodeCompress function
|
||||
GInfinityCopy1 := new(G2)
|
||||
GInfinityCopy1.Set(GInfinity)
|
||||
compressed = GInfinityCopy1.EncodeCompressed()
|
||||
|
||||
// Encode GaCopy2 with the Marshal function
|
||||
GInfinityCopy2 := new(G2)
|
||||
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,
|
||||
compressed[1:], // Ignore the masking byte
|
||||
marshalled[:64],
|
||||
"The EncodeCompressed and Marshal function yield different results")
|
||||
|
||||
// Unmarshal the point Ga with the unmarshal function
|
||||
Gb1 = new(G2)
|
||||
_, 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(G2)
|
||||
err = Gb2.DecodeCompressed(compressed)
|
||||
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")
|
||||
}
|
||||
|
||||
func TestG2DecodeUncompressed(t *testing.T) {
|
||||
// == Case1: Create random point (Jacobian form) == //
|
||||
_, GaInit, err := RandomG2(rand.Reader)
|
||||
assert.NoError(t, err, "Err should be nil")
|
||||
|
||||
// Affine form of GaInit
|
||||
GaAffine := new(G2)
|
||||
GaAffine.Set(GaInit)
|
||||
GaAffine.p.MakeAffine()
|
||||
|
||||
// Encode GaCopy1 with the EncodeUncompress function
|
||||
GaCopy1 := new(G2)
|
||||
GaCopy1.Set(GaInit)
|
||||
encoded := GaCopy1.EncodeUncompressed()
|
||||
|
||||
// Encode GaCopy2 with the Marshal function
|
||||
GaCopy2 := new(G2)
|
||||
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(G2)
|
||||
_, 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(G2)
|
||||
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(G2)
|
||||
GInfinity.p = &twistPoint{}
|
||||
GInfinity.p.SetInfinity()
|
||||
|
||||
// Get the point in affine form
|
||||
GInfinityAffine := new(G2)
|
||||
GInfinityAffine.Set(GInfinity)
|
||||
GInfinityAffine.p.MakeAffine()
|
||||
|
||||
// Encode GaCopy1 with the EncodeUncompress function
|
||||
GInfinityCopy1 := new(G2)
|
||||
GInfinityCopy1.Set(GInfinity)
|
||||
encoded = GInfinityCopy1.EncodeUncompressed()
|
||||
|
||||
// Encode GaCopy2 with the Marshal function
|
||||
GInfinityCopy2 := new(G2)
|
||||
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(G2)
|
||||
_, 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(G2)
|
||||
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")
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
package bn256
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// FpUint64Size is the number of uint64 chunks to represent a field element
|
||||
const FpUint64Size = 4
|
||||
|
||||
type gfP [FpUint64Size]uint64
|
||||
|
||||
func newGFp(x int64) (out *gfP) {
|
||||
if x >= 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}) }
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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.<j> = PolynomialRing(Fp, 'j')
|
||||
// The modulus is in the form `j^2 - non-residue-in-Fp`
|
||||
// Fp2.<i> = 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.<i> = 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")
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
@ -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
|
@ -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)
|
@ -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
|
||||
}
|
||||
*/
|
@ -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())
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
@ -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=
|
@ -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 <k,0,0,...> 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 <k,0,0,...>.
|
||||
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))
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
@ -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)")
|
||||
}
|
||||
}
|
@ -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)
|
@ -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
|
@ -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)
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
// <sage>
|
||||
// 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()
|
||||
}
|
102
crypto/bnred.go
102
crypto/bnred.go
@ -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
|
||||
}
|
||||
*/
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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])
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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<<j)+i < n; j++ {
|
||||
i1 := (1 << j) + i
|
||||
if !bits[i1] {
|
||||
temp := new(big.Int).Mod(new(big.Int).Mul(challenges[log_n-1-j], challenges[log_n-1-j]), bn256.Order)
|
||||
exponents[i1] = new(big.Int).Mod(new(big.Int).Mul(exponents[i], temp), bn256.Order)
|
||||
bits[i1] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var zeroes [64]byte
|
||||
gtemp := new(bn256.G1) // obtain zero element, this should be static and
|
||||
htemp := new(bn256.G1) // obtain zero element, this should be static and
|
||||
|
||||
gtemp.Unmarshal(zeroes[:])
|
||||
htemp.Unmarshal(zeroes[:])
|
||||
|
||||
for i := uint(0); i < n; i++ {
|
||||
gtemp = new(bn256.G1).Add(gtemp, new(bn256.G1).ScalarMult(gp.Gs.vector[i], exponents[i]))
|
||||
htemp = new(bn256.G1).Add(htemp, new(bn256.G1).ScalarMult(hs[i], exponents[n-1-i]))
|
||||
}
|
||||
gtemp = new(bn256.G1).ScalarMult(gtemp, ip.a)
|
||||
htemp = new(bn256.G1).ScalarMult(htemp, ip.b)
|
||||
utemp := new(bn256.G1).ScalarMult(u, new(big.Int).Mod(new(big.Int).Mul(ip.a, ip.b), bn256.Order))
|
||||
|
||||
P_calculated := new(bn256.G1).Add(gtemp, htemp)
|
||||
P_calculated = new(bn256.G1).Add(P_calculated, utemp)
|
||||
|
||||
// fmt.Printf("P %s\n",P.String())
|
||||
// fmt.Printf("P_calculated %s\n",P_calculated.String())
|
||||
|
||||
if P_calculated.String() != P.String() { // need something better here
|
||||
panic("Faulty or invalid proof")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -1,534 +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 "crypto/rand"
|
||||
import "encoding/hex"
|
||||
|
||||
import "github.com/deroproject/derohe/crypto/bn256"
|
||||
|
||||
//import "golang.org/x/crypto/sha3"
|
||||
|
||||
//import "github.com/kubernetes/klog"
|
||||
|
||||
// below 2 structures form bulletproofs and many to many proofs
|
||||
type AnonSupport struct {
|
||||
v *big.Int
|
||||
w *big.Int
|
||||
vPow *big.Int
|
||||
wPow *big.Int
|
||||
f [][2]*big.Int
|
||||
r [][2]*big.Int
|
||||
temp *bn256.G1
|
||||
CLnR *bn256.G1
|
||||
CRnR *bn256.G1
|
||||
CR [][2]*bn256.G1
|
||||
yR [][2]*bn256.G1
|
||||
C_XR *bn256.G1
|
||||
y_XR *bn256.G1
|
||||
gR *bn256.G1
|
||||
DR *bn256.G1
|
||||
}
|
||||
|
||||
type ProtocolSupport struct {
|
||||
y *big.Int
|
||||
ys []*big.Int
|
||||
z *big.Int
|
||||
zs []*big.Int // [z^2, z^3] // only max 2
|
||||
twoTimesZSquared [128]*big.Int
|
||||
zSum *big.Int
|
||||
x *big.Int
|
||||
t *big.Int
|
||||
k *big.Int
|
||||
tEval *bn256.G1
|
||||
}
|
||||
|
||||
// sigma protocol
|
||||
type SigmaSupport struct {
|
||||
c *big.Int
|
||||
A_y, A_D, A_b, A_X, A_t, A_u *bn256.G1
|
||||
}
|
||||
|
||||
// support structures are those which
|
||||
type InnerProductSupport struct {
|
||||
P bn256.G1
|
||||
u_x bn256.G1
|
||||
hPrimes []*bn256.G1
|
||||
hPrimeSum bn256.G1
|
||||
o *big.Int
|
||||
}
|
||||
|
||||
func unmarshalpoint(input string) *bn256.G1 {
|
||||
d, err := hex.DecodeString(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(d) != 64 {
|
||||
panic("wrong length")
|
||||
}
|
||||
|
||||
x := new(bn256.G1)
|
||||
x.Unmarshal(d)
|
||||
return x
|
||||
|
||||
}
|
||||
|
||||
var gparams = NewGeneratorParams(128) // these can be pregenerated similarly as in DERO project
|
||||
|
||||
// verify proof
|
||||
// first generate supporting structures
|
||||
func (proof *Proof) Verify(s *Statement, txid Hash) bool {
|
||||
|
||||
var anonsupport AnonSupport
|
||||
var protsupport ProtocolSupport
|
||||
var sigmasupport SigmaSupport
|
||||
|
||||
if len(s.C) != len(s.Publickeylist) {
|
||||
return false
|
||||
}
|
||||
|
||||
statementhash := reducedhash(txid[:])
|
||||
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()...)
|
||||
anonsupport.v = reducedhash(input)
|
||||
|
||||
anonsupport.w = proof.hashmash1(anonsupport.v)
|
||||
|
||||
m := proof.f.Length() / 2
|
||||
N := int(math.Pow(2, float64(m)))
|
||||
|
||||
anonsupport.f = make([][2]*big.Int, 2*m, 2*m)
|
||||
|
||||
for k := 0; k < 2*m; k++ {
|
||||
anonsupport.f[k][1] = new(big.Int).Set(proof.f.vector[k])
|
||||
anonsupport.f[k][0] = new(big.Int).Mod(new(big.Int).Sub(anonsupport.w, proof.f.vector[k]), bn256.Order)
|
||||
}
|
||||
|
||||
anonsupport.temp = new(bn256.G1)
|
||||
var zeroes [64]byte
|
||||
anonsupport.temp.Unmarshal(zeroes[:])
|
||||
|
||||
for k := 0; k < 2*m; k++ {
|
||||
anonsupport.temp = new(bn256.G1).Add(anonsupport.temp, new(bn256.G1).ScalarMult(gparams.Gs.vector[k], anonsupport.f[k][1]))
|
||||
|
||||
t := new(big.Int).Mod(new(big.Int).Mul(anonsupport.f[k][1], anonsupport.f[k][0]), bn256.Order)
|
||||
|
||||
anonsupport.temp = new(bn256.G1).Add(anonsupport.temp, new(bn256.G1).ScalarMult(gparams.Hs.vector[k], t))
|
||||
}
|
||||
|
||||
t0 := new(bn256.G1).ScalarMult(gparams.Hs.vector[0+2*m], new(big.Int).Mod(new(big.Int).Mul(anonsupport.f[0][1], anonsupport.f[m][1]), bn256.Order))
|
||||
t1 := new(bn256.G1).ScalarMult(gparams.Hs.vector[1+2*m], new(big.Int).Mod(new(big.Int).Mul(anonsupport.f[0][0], anonsupport.f[m][0]), bn256.Order))
|
||||
|
||||
anonsupport.temp = new(bn256.G1).Add(anonsupport.temp, t0)
|
||||
anonsupport.temp = new(bn256.G1).Add(anonsupport.temp, t1)
|
||||
|
||||
// check whether we successfuly recover B^w * A
|
||||
stored := new(bn256.G1).Add(new(bn256.G1).ScalarMult(proof.B, anonsupport.w), proof.A)
|
||||
computed := new(bn256.G1).Add(anonsupport.temp, new(bn256.G1).ScalarMult(gparams.H, proof.z_A))
|
||||
|
||||
// for i := range proof.f.vector {
|
||||
// klog.V(2).Infof("proof.f %d %s\n", i, proof.f.vector[i].Text(16))
|
||||
// }
|
||||
// klog.V(2).Infof("anonsupport.w %s\n", anonsupport.w.Text(16))
|
||||
// klog.V(2).Infof("proof.z_A %s\n", proof.z_A.Text(16))
|
||||
// klog.V(2).Infof("proof.B %s\n", proof.B.String())
|
||||
// klog.V(2).Infof("proof.A %s\n", proof.A.String())
|
||||
// klog.V(2).Infof("gparams.H %s\n", gparams.H.String())
|
||||
|
||||
// klog.V(2).Infof("stored %s\n", stored.String())
|
||||
// klog.V(2).Infof("computed %s\n", computed.String())
|
||||
|
||||
if stored.String() != computed.String() { // if failed bail out
|
||||
// klog.Warning("Recover key failed B^w * A")
|
||||
return false
|
||||
}
|
||||
|
||||
anonsupport.r = assemblepolynomials(anonsupport.f)
|
||||
|
||||
// for i := 0; i < len(anonsupport.r); i++ {
|
||||
// klog.V(2).Infof("proof.r %d %s\n", i, anonsupport.r[i][0].Text(16))
|
||||
// }
|
||||
// for i := 0; i < len(anonsupport.r); i++ {
|
||||
// klog.V(2).Infof("proof.q %d %s\n", i, anonsupport.r[i][1].Text(16))
|
||||
// }
|
||||
|
||||
anonsupport.CLnR = new(bn256.G1)
|
||||
anonsupport.CRnR = new(bn256.G1)
|
||||
anonsupport.CLnR.Unmarshal(zeroes[:])
|
||||
anonsupport.CRnR.Unmarshal(zeroes[:])
|
||||
for i := 0; i < N; i++ {
|
||||
anonsupport.CLnR = new(bn256.G1).Add(anonsupport.CLnR, new(bn256.G1).ScalarMult(s.CLn[i], anonsupport.r[i][0]))
|
||||
anonsupport.CRnR = new(bn256.G1).Add(anonsupport.CRnR, new(bn256.G1).ScalarMult(s.CRn[i], anonsupport.r[i][0]))
|
||||
}
|
||||
|
||||
// klog.V(2).Infof("qCrnR %s\n", anonsupport.CRnR.String())
|
||||
|
||||
var p, q []*big.Int
|
||||
for i := 0; i < len(anonsupport.r); i++ {
|
||||
p = append(p, anonsupport.r[i][0])
|
||||
q = append(q, anonsupport.r[i][1])
|
||||
}
|
||||
|
||||
// for i := range s.C {
|
||||
// klog.V(2).Infof("S.c %d %s \n", i, s.C[i].String())
|
||||
// }
|
||||
// share code with proof generator for better testing
|
||||
C_p := Convolution(NewFieldVector(p), NewPointVector(s.C))
|
||||
C_q := Convolution(NewFieldVector(q), NewPointVector(s.C))
|
||||
y_p := Convolution(NewFieldVector(p), NewPointVector(s.Publickeylist))
|
||||
y_q := Convolution(NewFieldVector(q), NewPointVector(s.Publickeylist))
|
||||
|
||||
// for i := range s.C {
|
||||
// klog.V(2).Infof("S.c %d %s \n", i, s.C[i].String())
|
||||
// }
|
||||
|
||||
// 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())
|
||||
// }
|
||||
|
||||
for i := range C_p.vector { // assemble back
|
||||
anonsupport.CR = append(anonsupport.CR, [2]*bn256.G1{C_p.vector[i], C_q.vector[i]})
|
||||
anonsupport.yR = append(anonsupport.yR, [2]*bn256.G1{y_p.vector[i], y_q.vector[i]})
|
||||
}
|
||||
|
||||
anonsupport.vPow = new(big.Int).SetUint64(1)
|
||||
|
||||
anonsupport.C_XR = new(bn256.G1)
|
||||
anonsupport.y_XR = new(bn256.G1)
|
||||
anonsupport.C_XR.Unmarshal(zeroes[:])
|
||||
anonsupport.y_XR.Unmarshal(zeroes[:])
|
||||
for i := 0; i < N; i++ {
|
||||
anonsupport.C_XR.Add(new(bn256.G1).Set(anonsupport.C_XR), new(bn256.G1).ScalarMult(anonsupport.CR[i/2][i%2], anonsupport.vPow))
|
||||
anonsupport.y_XR.Add(new(bn256.G1).Set(anonsupport.y_XR), new(bn256.G1).ScalarMult(anonsupport.yR[i/2][i%2], anonsupport.vPow))
|
||||
|
||||
if i > 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
|
||||
}
|
@ -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
|
||||
}
|
||||
*/
|
@ -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
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
@ -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 }
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
@ -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
|
@ -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)
|
||||
}
|
@ -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...)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
BIN
crypto/sha3/testdata/keccakKats.json.deflate
vendored
BIN
crypto/sha3/testdata/keccakKats.json.deflate
vendored
Binary file not shown.
@ -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"
|
@ -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:]
|
||||
}
|
||||
}
|
@ -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"
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user