From 30581274a1b10461702222c62b273c60f5d52de0 Mon Sep 17 00:00:00 2001 From: Wanwiset Peerapatanapokin Date: Sun, 11 Feb 2024 01:51:11 +0400 Subject: [PATCH] RIN-08 RIN-10 RIN-11 Fix curve issues (#425) * update secp256k1 library from go-eth code * cast deprecated functions to use new BitCurve type * add IsOnCurve checks and tests * add test outcome check --- core/vm/privacy/ringct.go | 26 ++++- core/vm/privacy/ringct_test.go | 100 ++++++++++++++++++ crypto/secp256k1/LICENSE | 31 ++++++ crypto/secp256k1/curve.go | 93 +++++++--------- crypto/secp256k1/dummy.go | 21 ++++ crypto/secp256k1/ext.h | 18 +--- .../secp256k1/libsecp256k1/contrib/dummy.go | 8 ++ crypto/secp256k1/libsecp256k1/dummy.go | 8 ++ .../secp256k1/libsecp256k1/include/dummy.go | 8 ++ .../libsecp256k1/src/asm/field_10x26_arm.s | 4 +- crypto/secp256k1/libsecp256k1/src/dummy.go | 8 ++ .../libsecp256k1/src/modules/dummy.go | 8 ++ .../libsecp256k1/src/modules/ecdh/dummy.go | 8 ++ .../src/modules/recovery/dummy.go | 8 ++ crypto/secp256k1/libsecp256k1/src/num.h | 2 +- crypto/secp256k1/libsecp256k1/src/secp256k1.c | 2 - crypto/secp256k1/panic_cb.go | 21 ++-- crypto/secp256k1/scalar_mult_cgo.go | 57 ++++++++++ crypto/secp256k1/scalar_mult_nocgo.go | 14 +++ crypto/secp256k1/secp256.go | 41 +++---- crypto/secp256k1/secp256_test.go | 62 +++++------ 21 files changed, 410 insertions(+), 138 deletions(-) create mode 100644 crypto/secp256k1/LICENSE create mode 100644 crypto/secp256k1/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/contrib/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/include/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/src/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go create mode 100644 crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go create mode 100644 crypto/secp256k1/scalar_mult_cgo.go create mode 100644 crypto/secp256k1/scalar_mult_nocgo.go diff --git a/core/vm/privacy/ringct.go b/core/vm/privacy/ringct.go index 9e70ddddf2..d52407b311 100644 --- a/core/vm/privacy/ringct.go +++ b/core/vm/privacy/ringct.go @@ -13,6 +13,8 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/crypto" + "github.com/XinFinOrg/XDPoSChain/crypto/secp256k1" + "github.com/XinFinOrg/XDPoSChain/log" ) @@ -259,6 +261,10 @@ func Deserialize(r []byte) (*RingSignature, error) { sig.SerializedRing = r + if !Verify(sig, false) { + return nil, errors.New("failed to deserialize, invalid ring signature") + } + return sig, nil } @@ -357,7 +363,8 @@ func Sign(m [32]byte, rings []Ring, privkeys []*ecdsa.PrivateKey, s int) (*RingS for i := 0; i < numRing; i++ { pubkeys[i] = &privkeys[i].PublicKey } - curve := pubkeys[0].Curve + //cast to BitCurve used in go-eth since elliptic.Curve.Add() and elliptic.Curve.ScalarMult() is deprecated + curve := pubkeys[0].Curve.(*secp256k1.BitCurve) sig := new(RingSignature) sig.Size = ringsize sig.NumRing = numRing @@ -504,9 +511,24 @@ func Verify(sig *RingSignature, verifyMes bool) bool { S := sig.S C := make([]*big.Int, ringsize+1) C[0] = sig.C - curve := sig.Curve + //cast to BitCurve used in go-eth since elliptic.Curve.Add() and elliptic.Curve.ScalarMult() is deprecated + curve := sig.Curve.(*secp256k1.BitCurve) image := sig.I + //check on curve + for i := 0; i < numRing; i++ { + onCurve := curve.IsOnCurve(image[i].X, image[i].Y) + if !onCurve { + return false + } + for j := 0; j < ringsize; j++ { + onCurve := curve.IsOnCurve(rings[i][j].X, rings[i][j].Y) + if !onCurve { + return false + } + } + } + // calculate c[i+1] = H(m, s[i]*G + c[i]*P[i]) // and c[0] = H)(m, s[n-1]*G + c[n-1]*P[n-1]) where n is the ring size //log.Info("C", "0", common.Bytes2Hex(C[0].Bytes())) diff --git a/core/vm/privacy/ringct_test.go b/core/vm/privacy/ringct_test.go index faef37f86a..49dbc3a5ab 100644 --- a/core/vm/privacy/ringct_test.go +++ b/core/vm/privacy/ringct_test.go @@ -9,6 +9,8 @@ import ( "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/stretchr/testify/assert" + + "github.com/XinFinOrg/XDPoSChain/crypto/secp256k1" ) func TestSign(t *testing.T) { @@ -130,6 +132,104 @@ func TestPadTo32Bytes(t *testing.T) { assert.True(t, bytes.Equal(PadTo32Bytes(arr[10:41]), arr[9:41]), "Test PadTo32Bytes shorter than 32 bytes #10") } +func TestCurveAddNegative(t *testing.T) { + curve := crypto.S256().(*secp256k1.BitCurve) + + x1, y1 := curve.ScalarBaseMult(new(big.Int).SetUint64(uint64(2)).Bytes()) + fmt.Printf("Point(%x, %x)\n", x1, y1) + + x2 := x1 + y2 := new(big.Int).Neg(y1) // negative of point (x1,y1) + + x3, y3 := curve.Add(x1, y1, x2, y2) + fmt.Printf("Output is Point(%x, %x)\n", x3, y3) + + x0 := new(big.Int).SetUint64(uint64(0)) + y0 := new(big.Int).SetUint64(uint64(0)) // infinity + + if (x3.Cmp(x0) == 0) && (y3.Cmp(y0) == 0) { + // fmt.Printf("Correct, add negative of self should yield (0,0)") + } else { + t.Error("Incorrect, add negative of self did not yield (0,0)") + } +} + +func TestCurveAddZero(t *testing.T) { + // curve := crypto.S256() + curve := crypto.S256().(*secp256k1.BitCurve) + + x1, y1 := curve.ScalarBaseMult(new(big.Int).SetUint64(uint64(1)).Bytes()) + fmt.Printf("Point(%x, %x)\n", x1, y1) + + x0 := new(big.Int).SetUint64(uint64(0)) + y0 := new(big.Int).SetUint64(uint64(0)) // infinity + fmt.Printf("Is point (%d,%d) on the curve: %t \n", x0, y0, curve.IsOnCurve(x0, y0)) + + x2, y2 := curve.Add(x1, y1, x0, y0) + fmt.Printf("Output is Point(%x, %x)\n", x2, y2) + + if (x1.Cmp(x2) == 0) && (y1.Cmp(y2) == 0) { + // fmt.Printf("Correct, Point on curve is the same after Zero addition\n") + } else { + t.Error("Incorrect, Point on curve changed after Zero addition\n") + } +} + +func TestOnCurveVerify(t *testing.T) { + numRing := 5 + ringSize := 10 + s := 5 + rings, privkeys, m, err := GenerateMultiRingParams(numRing, ringSize, s) + ringSignature, err := Sign(m, rings, privkeys, s) + if err != nil { + t.Error("Failed to create Ring signature") + } + + valid := Verify(ringSignature, false) + if !valid { + t.Error("Incorrect, unmodified ringSignature should be valid") + } + + ringsModified := ringSignature.Ring + ringsModified[0][0].X = big.NewInt(1) + ringsModified[0][0].Y = big.NewInt(1) + valid = Verify(ringSignature, false) + if valid { + t.Error("Incorrect, modified ringSignature should be invalid") + } +} + +func TestOnCurveDeserialize(t *testing.T) { + numRing := 5 + ringSize := 10 + s := 5 + rings, privkeys, m, err := GenerateMultiRingParams(numRing, ringSize, s) + ringSignature, err := Sign(m, rings, privkeys, s) + if err != nil { + t.Error("Failed to create Ring signature") + } + + sig, err := ringSignature.Serialize() + if err != nil { + t.Error("Failed to Serialize input Ring signature") + } + _, err = Deserialize(sig) + if err != nil { + t.Error("Failed to Deserialize") + } + + ringsModified := ringSignature.Ring + ringsModified[0][0].X = big.NewInt(1) + ringsModified[0][0].Y = big.NewInt(1) + + sig, err = ringSignature.Serialize() + if err != nil { + t.Error("Failed to Serialize input Ring signature") + } + _, err = Deserialize(sig) + assert.EqualError(t, err, "failed to deserialize, invalid ring signature") +} + func TestCurveScalarMult(t *testing.T) { curve := crypto.S256() diff --git a/crypto/secp256k1/LICENSE b/crypto/secp256k1/LICENSE new file mode 100644 index 0000000000..f9090e1423 --- /dev/null +++ b/crypto/secp256k1/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2010 The Go Authors. All rights reserved. +Copyright (c) 2011 ThePiachu. All rights reserved. +Copyright (c) 2015 Jeffrey Wilcke. All rights reserved. +Copyright (c) 2015 Felix Lange. All rights reserved. +Copyright (c) 2015 Gustav Simonsson. 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 the copyright holder. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index ecf7a238f0..9b26ab2928 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -1,5 +1,6 @@ // Copyright 2010 The Go Authors. All rights reserved. // Copyright 2011 ThePiachu. All rights reserved. +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -34,16 +35,28 @@ package secp256k1 import ( "crypto/elliptic" "math/big" - "unsafe" - - "github.com/XinFinOrg/XDPoSChain/common/math" ) -/* -#include "libsecp256k1/include/secp256k1.h" -extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar); -*/ -import "C" +const ( + // number of bits in a big.Word + wordBits = 32 << (uint64(^big.Word(0)) >> 63) + // number of bytes in a big.Word + wordBytes = wordBits / 8 +) + +// readBits encodes the absolute value of bigint as big-endian bytes. Callers +// must ensure that buf has enough space. If buf is too short the result will +// be incomplete. +func readBits(bigint *big.Int, buf []byte) { + i := len(buf) + for _, d := range bigint.Bits() { + for j := 0; j < wordBytes && i > 0; j++ { + i-- + buf[i] = byte(d) + d >>= 8 + } + } +} // This code is from https://github.com/ThePiachu/GoBit and implements // several Koblitz elliptic curves over prime fields. @@ -77,7 +90,7 @@ func (BitCurve *BitCurve) Params() *elliptic.CurveParams { } } -// IsOnBitCurve returns true if the given (x,y) lies on the BitCurve. +// IsOnCurve returns true if the given (x,y) lies on the BitCurve. func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² @@ -92,7 +105,6 @@ func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { return x3.Cmp(y2) == 0 } -//TODO: double check if the function is okay // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { @@ -113,7 +125,18 @@ func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big. // Add returns the sum of (x1,y1) and (x2,y2) func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + // If one point is at infinity, return the other point. + // Adding the point at infinity to any point will preserve the other point. + if x1.Sign() == 0 && y1.Sign() == 0 { + return x2, y2 + } + if x2.Sign() == 0 && y2.Sign() == 0 { + return x1, y1 + } z := new(big.Int).SetInt64(1) + if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 { + return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z)) + } return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z)) } @@ -222,40 +245,6 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, return x3, y3, z3 } -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { - // Ensure scalar is exactly 32 bytes. We pad always, even if - // scalar is 32 bytes long, to avoid a timing side channel. - if len(scalar) > 32 { - panic("can't handle scalars > 256 bits") - } - // NOTE: potential timing issue - padded := make([]byte, 32) - copy(padded[32-len(scalar):], scalar) - scalar = padded - - // Do the multiplication in C, updating point. - point := make([]byte, 64) - math.ReadBits(Bx, point[:32]) - math.ReadBits(By, point[32:]) - pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) - scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) - res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr) - - // Unpack the result and clear temporaries. - x := new(big.Int).SetBytes(point[:32]) - y := new(big.Int).SetBytes(point[32:]) - for i := range point { - point[i] = 0 - } - for i := range padded { - scalar[i] = 0 - } - if res != 1 { - return nil, nil - } - return x, y -} - // ScalarBaseMult returns k*G, where G is the base point of the group and k is // an integer in big-endian form. func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { @@ -268,8 +257,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { byteLen := (BitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag - math.ReadBits(x, ret[1:1+byteLen]) - math.ReadBits(y, ret[1+byteLen:]) + readBits(x, ret[1:1+byteLen]) + readBits(y, ret[1+byteLen:]) return ret } @@ -293,12 +282,12 @@ var theCurve = new(BitCurve) func init() { // See SEC 2 section 2.7.1 // curve parameters taken from: - // http://www.secg.org/collateral/sec2_final.pdf - theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) - theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) - theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) - theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) + // http://www.secg.org/sec2-v2.pdf + theCurve.P, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 0) + theCurve.N, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 0) + theCurve.B, _ = new(big.Int).SetString("0x0000000000000000000000000000000000000000000000000000000000000007", 0) + theCurve.Gx, _ = new(big.Int).SetString("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 0) + theCurve.Gy, _ = new(big.Int).SetString("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 0) theCurve.BitSize = 256 } diff --git a/crypto/secp256k1/dummy.go b/crypto/secp256k1/dummy.go new file mode 100644 index 0000000000..65a75080f6 --- /dev/null +++ b/crypto/secp256k1/dummy.go @@ -0,0 +1,21 @@ +//go:build dummy +// +build dummy + +// This file is part of a workaround for `go mod vendor` which won't vendor +// C files if there's no Go file in the same directory. +// This would prevent the crypto/secp256k1/libsecp256k1/include/secp256k1.h file to be vendored. +// +// This Go file imports the c directory where there is another dummy.go file which +// is the second part of this workaround. +// +// These two files combined make it so `go mod vendor` behaves correctly. +// +// See this issue for reference: https://github.com/golang/go/issues/26366 + +package secp256k1 + +import ( + _ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/include" + _ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/src" + _ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/src/modules/recovery" +) diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h index 9b043c724e..e422fe4b49 100644 --- a/crypto/secp256k1/ext.h +++ b/crypto/secp256k1/ext.h @@ -1,18 +1,6 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. // secp256k1_context_create_sign_verify creates a context for signing and signature verification. static secp256k1_context* secp256k1_context_create_sign_verify() { diff --git a/crypto/secp256k1/libsecp256k1/contrib/dummy.go b/crypto/secp256k1/libsecp256k1/contrib/dummy.go new file mode 100644 index 0000000000..2c946210c5 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/contrib/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package contrib diff --git a/crypto/secp256k1/libsecp256k1/dummy.go b/crypto/secp256k1/libsecp256k1/dummy.go new file mode 100644 index 0000000000..04bbe3d76e --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package libsecp256k1 diff --git a/crypto/secp256k1/libsecp256k1/include/dummy.go b/crypto/secp256k1/libsecp256k1/include/dummy.go new file mode 100644 index 0000000000..64c71b8451 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/include/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package include diff --git a/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s index 5df561f2fc..5a9cc3ffcf 100644 --- a/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s +++ b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s @@ -11,7 +11,7 @@ Note: - To avoid unnecessary loads and make use of available registers, two 'passes' have every time been interleaved, with the odd passes accumulating c' and d' - which will be added to c and d respectively in the the even passes + which will be added to c and d respectively in the even passes */ @@ -23,7 +23,7 @@ Note: .eabi_attribute 10, 0 @ Tag_FP_arch = none .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP - .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 .text diff --git a/crypto/secp256k1/libsecp256k1/src/dummy.go b/crypto/secp256k1/libsecp256k1/src/dummy.go new file mode 100644 index 0000000000..2df270adc3 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package src diff --git a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go new file mode 100644 index 0000000000..99c538db51 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package module diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go new file mode 100644 index 0000000000..48c2e0aa54 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package ecdh diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go new file mode 100644 index 0000000000..8efbd7abe7 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go @@ -0,0 +1,8 @@ +//go:build dummy +// +build dummy + +// Package c contains only a C file. +// +// This Go file is part of a workaround for `go mod vendor`. +// Please see the file crypto/secp256k1/dummy.go for more information. +package recovery diff --git a/crypto/secp256k1/libsecp256k1/src/num.h b/crypto/secp256k1/libsecp256k1/src/num.h index 7bb9c5be8c..eff842200f 100644 --- a/crypto/secp256k1/libsecp256k1/src/num.h +++ b/crypto/secp256k1/libsecp256k1/src/num.h @@ -54,7 +54,7 @@ static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const se even if r was negative. */ static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); -/** Right-shift the passed number by bits bits. */ +/** Right-shift the passed number by bits. */ static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ diff --git a/crypto/secp256k1/libsecp256k1/src/secp256k1.c b/crypto/secp256k1/libsecp256k1/src/secp256k1.c index fb8b882faa..7d637bfad1 100755 --- a/crypto/secp256k1/libsecp256k1/src/secp256k1.c +++ b/crypto/secp256k1/libsecp256k1/src/secp256k1.c @@ -26,7 +26,6 @@ } while(0) static void default_illegal_callback_fn(const char* str, void* data) { - (void)data; fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); abort(); } @@ -37,7 +36,6 @@ static const secp256k1_callback default_illegal_callback = { }; static void default_error_callback_fn(const char* str, void* data) { - (void)data; fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); abort(); } diff --git a/crypto/secp256k1/panic_cb.go b/crypto/secp256k1/panic_cb.go index e0e9034ee0..a30b04f51b 100644 --- a/crypto/secp256k1/panic_cb.go +++ b/crypto/secp256k1/panic_cb.go @@ -1,18 +1,9 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +//go:build !gofuzz && cgo +// +build !gofuzz,cgo package secp256k1 diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go new file mode 100644 index 0000000000..8afa9d023b --- /dev/null +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -0,0 +1,57 @@ +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +//go:build !gofuzz && cgo +// +build !gofuzz,cgo + +package secp256k1 + +import ( + "math/big" + "unsafe" +) + +/* + +#include "libsecp256k1/include/secp256k1.h" + +extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar); + +*/ +import "C" + +func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { + // Ensure scalar is exactly 32 bytes. We pad always, even if + // scalar is 32 bytes long, to avoid a timing side channel. + if len(scalar) > 32 { + panic("can't handle scalars > 256 bits") + } + // NOTE: potential timing issue + padded := make([]byte, 32) + copy(padded[32-len(scalar):], scalar) + scalar = padded + + // Do the multiplication in C, updating point. + point := make([]byte, 64) + readBits(Bx, point[:32]) + readBits(By, point[32:]) + + pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) + scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) + res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr) + + // Unpack the result and clear temporaries. + x := new(big.Int).SetBytes(point[:32]) + y := new(big.Int).SetBytes(point[32:]) + for i := range point { + point[i] = 0 + } + for i := range padded { + scalar[i] = 0 + } + if res != 1 { + return nil, nil + } + return x, y +} diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go new file mode 100644 index 0000000000..22f53ac6ae --- /dev/null +++ b/crypto/secp256k1/scalar_mult_nocgo.go @@ -0,0 +1,14 @@ +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +//go:build gofuzz || !cgo +// +build gofuzz !cgo + +package secp256k1 + +import "math/big" + +func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { + panic("ScalarMult is not available when secp256k1 is built without cgo") +} diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index eefbb99ee4..61abc1eaf0 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -1,18 +1,9 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +//go:build !gofuzz && cgo +// +build !gofuzz,cgo // Package secp256k1 wraps the bitcoin secp256k1 C library. package secp256k1 @@ -20,12 +11,24 @@ package secp256k1 /* #cgo CFLAGS: -I./libsecp256k1 #cgo CFLAGS: -I./libsecp256k1/src/ + +#ifdef __SIZEOF_INT128__ +# define HAVE___INT128 +# define USE_FIELD_5X52 +# define USE_SCALAR_4X64 +#else +# define USE_FIELD_10X26 +# define USE_SCALAR_8X32 +#endif + +#ifndef NDEBUG +# define NDEBUG +#endif + +#define USE_ENDOMORPHISM #define USE_NUM_NONE -#define USE_FIELD_10X26 #define USE_FIELD_INV_BUILTIN -#define USE_SCALAR_8X32 #define USE_SCALAR_INV_BUILTIN -#define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" #include "ext.h" @@ -98,7 +101,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { return sig, nil } -// RecoverPubkey returns the the public key of the signer. +// RecoverPubkey returns the public key of the signer. // msg must be the 32-byte hash of the message to be signed. // sig must be a 65-byte compact ECDSA signature containing the // recovery id as the last element. diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index f8902607b9..74408d06d2 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -1,18 +1,9 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . +// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +//go:build !gofuzz && cgo +// +build !gofuzz,cgo package secp256k1 @@ -22,10 +13,8 @@ import ( "crypto/elliptic" "crypto/rand" "encoding/hex" + "io" "testing" - - "github.com/XinFinOrg/XDPoSChain/common/math" - "github.com/XinFinOrg/XDPoSChain/crypto/randentropy" ) const TestCount = 1000 @@ -36,11 +25,24 @@ func generateKeyPair() (pubkey, privkey []byte) { panic(err) } pubkey = elliptic.Marshal(S256(), key.X, key.Y) - return pubkey, math.PaddedBigBytes(key.D, 32) + + privkey = make([]byte, 32) + blob := key.D.Bytes() + copy(privkey[32-len(blob):], blob) + + return pubkey, privkey +} + +func csprngEntropy(n int) []byte { + buf := make([]byte, n) + if _, err := io.ReadFull(rand.Reader, buf); err != nil { + panic("reading from crypto/rand failed: " + err.Error()) + } + return buf } func randSig() []byte { - sig := randentropy.GetEntropyCSPRNG(65) + sig := csprngEntropy(65) sig[32] &= 0x70 sig[64] %= 4 return sig @@ -49,7 +51,7 @@ func randSig() []byte { // tests for malleability // highest bit of signature ECDSA s value must be 0, in the 33th byte func compactSigCheck(t *testing.T, sig []byte) { - var b int = int(sig[32]) + var b = int(sig[32]) if b < 0 { t.Errorf("highest bit is negative: %d", b) } @@ -63,7 +65,7 @@ func compactSigCheck(t *testing.T, sig []byte) { func TestSignatureValidity(t *testing.T) { pubkey, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) @@ -86,7 +88,7 @@ func TestSignatureValidity(t *testing.T) { func TestInvalidRecoveryID(t *testing.T) { _, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, _ := Sign(msg, seckey) sig[64] = 99 _, err := RecoverPubkey(msg, sig) @@ -97,7 +99,7 @@ func TestInvalidRecoveryID(t *testing.T) { func TestSignAndRecover(t *testing.T) { pubkey1, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) @@ -148,7 +150,7 @@ func TestRandomMessagesWithRandomKeys(t *testing.T) { func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) { for i := 0; i < TestCount; i++ { pubkey1, seckey := keys() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, err := Sign(msg, seckey) if err != nil { t.Fatalf("signature error: %s", err) @@ -176,7 +178,7 @@ func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte) func TestRecoveryOfRandomSignature(t *testing.T) { pubkey1, _ := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) for i := 0; i < TestCount; i++ { // recovery can sometimes work, but if so should always give wrong pubkey @@ -189,11 +191,11 @@ func TestRecoveryOfRandomSignature(t *testing.T) { func TestRandomMessagesAgainstValidSig(t *testing.T) { pubkey1, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) sig, _ := Sign(msg, seckey) for i := 0; i < TestCount; i++ { - msg = randentropy.GetEntropyCSPRNG(32) + msg = csprngEntropy(32) pubkey2, _ := RecoverPubkey(msg, sig) // recovery can sometimes work, but if so should always give wrong pubkey if bytes.Equal(pubkey1, pubkey2) { @@ -219,7 +221,7 @@ func TestRecoverSanity(t *testing.T) { func BenchmarkSign(b *testing.B) { _, seckey := generateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -228,7 +230,7 @@ func BenchmarkSign(b *testing.B) { } func BenchmarkRecover(b *testing.B) { - msg := randentropy.GetEntropyCSPRNG(32) + msg := csprngEntropy(32) _, seckey := generateKeyPair() sig, _ := Sign(msg, seckey) b.ResetTimer()