DERO-HE STARGATE Testnet Release13

This commit is contained in:
Captain 2021-02-27 16:00:43 +00:00
parent 650b57b4cf
commit fd2a2eba7f
No known key found for this signature in database
GPG Key ID: 18CDB3ED5E85D2D4
86 changed files with 77 additions and 12941 deletions

View File

@ -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.

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -73,6 +73,10 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree
defer func() { defer func() {
// safety so if anything wrong happens, verification fails // safety so if anything wrong happens, verification fails
if r := recover(); r != nil { 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("Recovered while rewinding chain, Stack trace below block_hash ")
logger.Warnf("Stack trace \n%s", debug.Stack()) 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) balance, sc_parsed, found := chain.ReadSC(w_sc_tree, data_tree, scid)
if !found { if !found {
fmt.Printf("SC not found\n") rlog.Warnf("SC not found %s", scid)
err = fmt.Errorf("SC not found %s", scid)
return return
} }
// if we found the SC in parsed form, check whether entrypoint is found // if we found the SC in parsed form, check whether entrypoint is found
function, ok := sc_parsed.Functions[entrypoint] function, ok := sc_parsed.Functions[entrypoint]
if !ok { if !ok {
rlog.Warnf("stored SC does not contain entrypoint '%s' scid %s \n", entrypoint, scid) 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 return
} }
_ = function _ = function

View File

@ -25,6 +25,7 @@ import "golang.org/x/xerrors"
import "github.com/romana/rlog" import "github.com/romana/rlog"
import "github.com/deroproject/derohe/cryptography/crypto" 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/transaction"
import "github.com/deroproject/derohe/config" import "github.com/deroproject/derohe/config"
import "github.com/deroproject/derohe/rpc" 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++ { 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_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)
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 := 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) balance := new(crypto.ElGamal).Deserialize(balance_serialized)
echanges := crypto.ConstructElGamal(tx.Payloads[t].Statement.C[i], tx.Payloads[t].Statement.D) echanges := crypto.ConstructElGamal(tx.Payloads[t].Statement.C[i], tx.Payloads[t].Statement.D)
balance = balance.Add(echanges) // homomorphic addition of changes balance = balance.Add(echanges) // homomorphic addition of changes
tree.Put(key_compressed, balance.Serialize()) // reserialize and store 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)
}
} }
} }

View File

@ -28,6 +28,7 @@ import "github.com/romana/rlog"
import "sync" import "sync"
import "runtime/debug" import "runtime/debug"
import "golang.org/x/xerrors"
import "github.com/deroproject/graviton" import "github.com/deroproject/graviton"
//import "github.com/romana/rlog" //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++ { 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_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) _, 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 { if err != nil {
return fmt.Errorf("balance not obtained err %s\n", err) 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_compressed = append(tx.Payloads[t].Statement.Publickeylist_compressed, pcopy)
tx.Payloads[t].Statement.Publickeylist = append(tx.Payloads[t].Statement.Publickeylist, &p) 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 var ll, rr bn256.G1

View File

@ -188,6 +188,6 @@ func (DERO_RPC_APIS) GetTransaction(ctx context.Context, p rpc.GetTransaction_Pa
result.Status = "OK" result.Status = "OK"
err = nil err = nil
logger.Debugf("result %+v\n", result) //logger.Debugf("result %+v\n", result)
return return
} }

View File

@ -104,7 +104,7 @@ var Mainnet = CHAIN_CONFIG{Name: "mainnet",
} }
var Testnet = CHAIN_CONFIG{Name: "testnet", // testnet will always have last 3 bytes 0 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, P2P_Default_Port: 40401,
RPC_Default_Port: 40402, RPC_Default_Port: 40402,
Wallet_RPC_Default_Port: 40403, Wallet_RPC_Default_Port: 40403,

View File

@ -20,4 +20,4 @@ import "github.com/blang/semver"
// right now it has to be manually changed // right now it has to be manually changed
// do we need to include git commitsha?? // 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")

View File

@ -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.

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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/

View File

@ -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.

View File

@ -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)

View File

@ -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 `r1` 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.

View File

@ -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 &GT{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 &GT{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
}

View File

@ -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})
}
}

View File

@ -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}}

View File

@ -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
}
}

View File

@ -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) }

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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}) }

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
}
*/

View File

@ -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())
}
}

View File

@ -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
)

View File

@ -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=

View File

@ -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))
}
}

View File

@ -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")
}
}

View File

@ -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)")
}
}

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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()
}

View File

@ -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
}
*/

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
*/

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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 }

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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...)
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

Binary file not shown.

View File

@ -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"

View File

@ -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:]
}
}

View File

@ -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"

View File

@ -16,7 +16,7 @@
package p2p package p2p
import "fmt" //import "fmt"
//import "net" //import "net"
import "time" import "time"
@ -71,7 +71,7 @@ try_again:
request.TopoHeights = append(request.TopoHeights, 0) request.TopoHeights = append(request.TopoHeights, 0)
fill_common(&request.Common) // fill common info fill_common(&request.Common) // fill common info
if err := connection.RConn.Client.Call("Peer.Chain", request, &response); err != nil { 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 return
} }
// we have a response, see if its valid and try to add to get the blocks // 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]) orequest.Block_list = append(orequest.Block_list, response.Block_list[i])
fill_common(&orequest.Common) fill_common(&orequest.Common)
if err := connection.RConn.Client.Call("Peer.GetObject", orequest, &oresponse); err != nil { 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 return
} else { // process the response } else { // process the response
if err = connection.process_object_response(oresponse); err != nil { if err = connection.process_object_response(oresponse); err != nil {

View File

@ -158,11 +158,13 @@ func (w *Wallet_Memory) Sync_Wallet_Memory_With_Daemon() {
previous := w.account.Balance_Result.Data previous := w.account.Balance_Result.Data
var scid crypto.Hash var scid crypto.Hash
if _, _, err := w.GetEncryptedBalanceAtTopoHeight(scid, -1, w.GetAddress().String()); err == nil { 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.DecodeEncryptedBalance() // try to decode balance
w.SyncHistory(scid) // also update statement w.SyncHistory(scid) // also update statement
w.save_if_disk() // save wallet w.save_if_disk() // save wallet
} else {
w.save_if_disk() // save wallet
} }
} else { } else {
rlog.Infof("getbalance err %s", err) 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() { if strings.Contains(strings.ToLower(err.Error()), strings.ToLower(errormsg.ErrAccountUnregistered.Error())) && accountaddr == w.GetAddress().String() && scid.IsZero() {
w.Error = errormsg.ErrAccountUnregistered 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 return
} }