2021-12-04 16:42:11 +00:00

238 lines
6.7 KiB
Go

// 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 "golang.org/x/crypto/sha3"
import "github.com/deroproject/derohe/cryptography/bn256"
// 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
}
// placed from bn256/constant.go variable p, since it is not exported we use it like this
// p = p(u) = 36u^4 + 36u^3 + 24u^2 + 6u + 1
var FIELD_ORDER = bn256.P
// Number of elements in the field (often called `q`)
// n = n(u) = 36u^4 + 36u^3 + 18u^2 + 6u + 1
var GEN_ORDER = bn256.Order
var CURVE_B = new(big.Int).SetUint64(3)
// a = (p+1) / 4
var CURVE_A = new(big.Int).Div(new(big.Int).Add(FIELD_ORDER, new(big.Int).SetUint64(1)), new(big.Int).SetUint64(4))
func HashToPoint(seed *big.Int) *bn256.G1 {
y_squared := new(big.Int)
one := new(big.Int).SetUint64(1)
var xbytes, ybytes [32]byte
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 {
x.FillBytes(xbytes[:])
y.FillBytes(ybytes[:])
// fmt.Printf("liesoncurve test %+v xlen %d ylen %d\n\n\n", isOnCurve(x,y), len(x.FillBytes(xbytes[:])), len(y.FillBytes(ybytes[:])) )
var point bn256.G1
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 HashToPointOld(seed *big.Int) *bn256.G1 {
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
}*/