From 10d5605166fd958f423cf69a6b2700a8b506a0ea Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 26 Aug 2019 14:27:00 +0300 Subject: [PATCH 1/9] _pkg.dev: drop Checksum package Duplicates hash.Checksum slightly and doesn't seem to fit into master well. --- _pkg.dev/wire/util/Checksum/checksum.go | 33 ------------------------- 1 file changed, 33 deletions(-) delete mode 100644 _pkg.dev/wire/util/Checksum/checksum.go diff --git a/_pkg.dev/wire/util/Checksum/checksum.go b/_pkg.dev/wire/util/Checksum/checksum.go deleted file mode 100644 index 6282650c7..000000000 --- a/_pkg.dev/wire/util/Checksum/checksum.go +++ /dev/null @@ -1,33 +0,0 @@ -package checksum - -import ( - "bytes" - "encoding/binary" - - "github.com/CityOfZion/neo-go/pkg/crypto/hash" -) - -// Compare calculates the checksum of b -// then compares it with the `have` checksum passed as a parameter -func Compare(have uint32, b []byte) bool { - want := FromBytes(b) - return have == want -} - -// FromBuf calculates the checksum of a buffer -func FromBuf(buf *bytes.Buffer) uint32 { - - return FromBytes(buf.Bytes()) -} - -// FromBytes calculates the checksum of a byte slice -func FromBytes(buf []byte) uint32 { - b, err := hash.DoubleSha256(buf) - - if err != nil { - return 0 - } - - // checksum := SumSHA256(SumSHA256(buf.Bytes())) - return binary.LittleEndian.Uint32(b.Bytes()[:4]) -} From 5938ebb85bd0965d398ec15bed5c8e2f042e123c Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 26 Aug 2019 14:28:53 +0300 Subject: [PATCH 2/9] _pkg.dev: drop util/io package Unused. --- _pkg.dev/wire/util/io/io.go | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 _pkg.dev/wire/util/io/io.go diff --git a/_pkg.dev/wire/util/io/io.go b/_pkg.dev/wire/util/io/io.go deleted file mode 100644 index 89117c602..000000000 --- a/_pkg.dev/wire/util/io/io.go +++ /dev/null @@ -1,17 +0,0 @@ -package fileutils - -import ( - "os" -) - -// UpdateFile appends a byte slice to a file -func UpdateFile(filename string, data []byte) error { - - f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - - dataWNewline := append(data, []byte("\n")...) - - _, err = f.Write(dataWNewline) - err = f.Close() - return err -} From d7701fe7db595e3f293b43356f4f7fa057ef33f6 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 26 Aug 2019 14:42:56 +0300 Subject: [PATCH 3/9] _pkg.dev: drop util/ip package It's an unneccessary kludge, master gets its IP from config and that's it. --- _pkg.dev/wire/util/ip/ip.go | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 _pkg.dev/wire/util/ip/ip.go diff --git a/_pkg.dev/wire/util/ip/ip.go b/_pkg.dev/wire/util/ip/ip.go deleted file mode 100644 index 4de12e8bd..000000000 --- a/_pkg.dev/wire/util/ip/ip.go +++ /dev/null @@ -1,20 +0,0 @@ -package iputils - -import ( - "log" - "net" -) - -//GetLocalIP returns the ip address of the current node -// https://stackoverflow.com/a/37382208 -func GetLocalIP() net.IP { - conn, err := net.Dial("udp", "8.8.8.8:80") - if err != nil { - log.Fatal(err) - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP -} From 2275b9e4ada61c401c44ea487347cd29812dd379 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 26 Aug 2019 15:46:19 +0300 Subject: [PATCH 4/9] _pkg.dev: drop address pkg, move test into crypto address wrappers don't seem to fit well into master's code, so just drop 'em, but pick the testing function with good known input/output pair. --- _pkg.dev/wire/util/address/address.go | 43 ---------------------- _pkg.dev/wire/util/address/address_test.go | 17 --------- pkg/crypto/address_test.go | 14 ++++++- 3 files changed, 13 insertions(+), 61 deletions(-) delete mode 100644 _pkg.dev/wire/util/address/address.go delete mode 100644 _pkg.dev/wire/util/address/address_test.go diff --git a/_pkg.dev/wire/util/address/address.go b/_pkg.dev/wire/util/address/address.go deleted file mode 100644 index 08b0347af..000000000 --- a/_pkg.dev/wire/util/address/address.go +++ /dev/null @@ -1,43 +0,0 @@ -package address - -import ( - "github.com/CityOfZion/neo-go/pkg/crypto/base58" - "github.com/CityOfZion/neo-go/pkg/wire/util" -) - -// ToScriptHash converts an address to a script hash -func ToScriptHash(address string) string { - a, err := Uint160Decode(address) - if err != nil { - return "" - } - return a.String() - -} - -// ToReverseScriptHash converts an address to a reverse script hash -func ToReverseScriptHash(address string) string { - a, err := Uint160Decode(address) - if err != nil { - return "" - } - return a.ReverseString() -} - -// FromUint160 returns the "NEO address" from the given -// Uint160. -func FromUint160(u util.Uint160) (string, error) { - // Dont forget to prepend the Address version 0x17 (23) A - b := append([]byte{0x17}, u.Bytes()...) - return base58.CheckEncode(b) -} - -// Uint160Decode attempts to decode the given NEO address string -// into an Uint160. -func Uint160Decode(s string) (u util.Uint160, err error) { - b, err := base58.CheckDecode(s) - if err != nil { - return u, err - } - return util.Uint160DecodeBytes(b[1:21]) -} diff --git a/_pkg.dev/wire/util/address/address_test.go b/_pkg.dev/wire/util/address/address_test.go deleted file mode 100644 index af264a935..000000000 --- a/_pkg.dev/wire/util/address/address_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package address - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestScriptHash(t *testing.T) { - address := "AJeAEsmeD6t279Dx4n2HWdUvUmmXQ4iJvP" - - hash := ToScriptHash(address) - reverseHash := ToReverseScriptHash(address) - - assert.Equal(t, "b28427088a3729b2536d10122960394e8be6721f", reverseHash) - assert.Equal(t, "1f72e68b4e39602912106d53b229378a082784b2", hash) -} diff --git a/pkg/crypto/address_test.go b/pkg/crypto/address_test.go index b325adb43..c4d54fd2c 100644 --- a/pkg/crypto/address_test.go +++ b/pkg/crypto/address_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestUint160DecodeAddress(t *testing.T) { +func TestUint160DecodeEncodeAddress(t *testing.T) { addrs := []string{ "AMLr1CpPQtbEdiJdriX1HpRNMZUwbU2Huj", "AKtwd3DRXj3nL5kHMUoNsdnsCEVjnuuTFF", @@ -20,3 +20,15 @@ func TestUint160DecodeAddress(t *testing.T) { assert.Equal(t, addr, AddressFromUint160(val)) } } + +func TestUint160DecodeKnownAddress(t *testing.T) { + address := "AJeAEsmeD6t279Dx4n2HWdUvUmmXQ4iJvP" + + val, err := Uint160DecodeAddress(address) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "b28427088a3729b2536d10122960394e8be6721f", val.ReverseString()) + assert.Equal(t, "1f72e68b4e39602912106d53b229378a082784b2", val.String()) +} From b19190b32f353aa52a5e83ccf72467147e9af907 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 26 Aug 2019 18:44:38 +0300 Subject: [PATCH 5/9] _pkg.dev: drop crypto/elliptic It's the same implementation that we have in pkg/crypto (based on https://github.com/vsergeev/btckeygenie) but with tests preserved. I don't see any reason to port tests from it because even the pkg/crypto copy should go away to fix #245. --- _pkg.dev/crypto/elliptic/Readme.md | 18 -- _pkg.dev/crypto/elliptic/curves.go | 64 ----- _pkg.dev/crypto/elliptic/elliptic.go | 319 ---------------------- _pkg.dev/crypto/elliptic/elliptic_test.go | 231 ---------------- 4 files changed, 632 deletions(-) delete mode 100755 _pkg.dev/crypto/elliptic/Readme.md delete mode 100755 _pkg.dev/crypto/elliptic/curves.go delete mode 100755 _pkg.dev/crypto/elliptic/elliptic.go delete mode 100755 _pkg.dev/crypto/elliptic/elliptic_test.go diff --git a/_pkg.dev/crypto/elliptic/Readme.md b/_pkg.dev/crypto/elliptic/Readme.md deleted file mode 100755 index ea1033488..000000000 --- a/_pkg.dev/crypto/elliptic/Readme.md +++ /dev/null @@ -1,18 +0,0 @@ -## Package - Elliptic - -### Why - -The curve and arithmetic functions have been modularised, so that curves can be swapped in and out, without effecting the functionality. - -The modular arithmetic used is not specialised for a specific curve. - -In order to use this package, you must declare an ellipticcurve struct and then set the curve. - -Example: - -` - - curve = NewEllipticCurve(Secp256k1) - -` -If no curve is set, the default curve is the r1 curve used for NEO. The tests are done using the k1 curve, so in the elliptic_test.go file, the curve is changed accordingly. diff --git a/_pkg.dev/crypto/elliptic/curves.go b/_pkg.dev/crypto/elliptic/curves.go deleted file mode 100755 index 5b24bb638..000000000 --- a/_pkg.dev/crypto/elliptic/curves.go +++ /dev/null @@ -1,64 +0,0 @@ -package elliptic - -/* - This file was originally made by vsergeev. - - Modifications have been made under the MIT license. - License: MIT - - -*/ - -import ( - "math/big" -) - -var curve Curve - -type curveType string - -const ( - // Secp256r1 curve type - Secp256r1 curveType = "Secp256r1" - // Secp256k1 curve type - Secp256k1 curveType = "Secp256k1" -) - -// SetCurveSecp256r1 Will set the curve parameters to match Secp256r1 -func (ChosenCurve *Curve) SetCurveSecp256r1() { - ChosenCurve.P, _ = new(big.Int).SetString("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16) //Q - ChosenCurve.A, _ = new(big.Int).SetString("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16) - ChosenCurve.B, _ = new(big.Int).SetString("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16) - ChosenCurve.G.X, _ = new(big.Int).SetString("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16) - ChosenCurve.G.Y, _ = new(big.Int).SetString("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16) - ChosenCurve.N, _ = new(big.Int).SetString("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16) - ChosenCurve.H, _ = new(big.Int).SetString("01", 16) - ChosenCurve.Name = "Secp256r1" -} - -// SetCurveSecp256k1 Will set the curve parameters to match Secp256k1 -func (ChosenCurve *Curve) SetCurveSecp256k1() { - ChosenCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) - ChosenCurve.A, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000000", 16) - ChosenCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) - ChosenCurve.G.X, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) - ChosenCurve.G.Y, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) - ChosenCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - ChosenCurve.H, _ = new(big.Int).SetString("01", 16) - ChosenCurve.Name = "Secp256k1" -} - -//NewEllipticCurve will instantiate a new EllipticCurve -//Defaults to secp256r1 -func NewEllipticCurve(ct curveType) Curve { - var curve Curve - switch ct { - case Secp256k1: - curve.SetCurveSecp256k1() - case Secp256r1: - curve.SetCurveSecp256r1() - default: - curve.SetCurveSecp256r1() - } - return curve -} diff --git a/_pkg.dev/crypto/elliptic/elliptic.go b/_pkg.dev/crypto/elliptic/elliptic.go deleted file mode 100755 index a176c3021..000000000 --- a/_pkg.dev/crypto/elliptic/elliptic.go +++ /dev/null @@ -1,319 +0,0 @@ -/* -This file has been modified under the MIT license. -Original: https://github.com/vsergeev/btckeygenie -*/ - -package elliptic - -import ( - nativeelliptic "crypto/elliptic" - "encoding/hex" - "errors" - "fmt" - "math/big" -) - -// Point represents a point on an EllipticCurve. -type Point struct { - X *big.Int - Y *big.Int -} - -// Curve represents the parameters of a short Weierstrass equation elliptic curve. -/* y**2 = x**3 + a*x + b % p */ -type Curve struct { - A *big.Int - B *big.Int - P *big.Int - G Point - N *big.Int - H *big.Int - Name string -} - -// dump dumps the bytes of a point for debugging. -func (p *Point) dump() { - fmt.Print(p.format()) -} - -// format formats the bytes of a point for debugging. -func (p *Point) format() string { - if p.X == nil && p.Y == nil { - return "(inf,inf)" - } - return fmt.Sprintf("(%s,%s)", hex.EncodeToString(p.X.Bytes()), hex.EncodeToString(p.Y.Bytes())) -} - -// Params represent the paramters for the Elliptic Curve -func (ec Curve) Params() *nativeelliptic.CurveParams { - return &nativeelliptic.CurveParams{ - P: ec.P, - N: ec.N, - B: ec.B, - Gx: ec.G.X, - Gy: ec.G.Y, - BitSize: 256, - Name: ec.Name, - } -} - -/*** Modular Arithmetic ***/ - -/* NOTE: Returning a new z each time below is very space inefficient, but the - * alternate accumulator based design makes the point arithmetic functions look - * absolutely hideous. I may still change this in the future. */ - -// addMod computes z = (x + y) % p. -func addMod(x *big.Int, y *big.Int, p *big.Int) (z *big.Int) { - z = new(big.Int).Add(x, y) - z.Mod(z, p) - return z -} - -// subMod computes z = (x - y) % p. -func subMod(x *big.Int, y *big.Int, p *big.Int) (z *big.Int) { - z = new(big.Int).Sub(x, y) - z.Mod(z, p) - return z -} - -// mulMod computes z = (x * y) % p. -func mulMod(x *big.Int, y *big.Int, p *big.Int) (z *big.Int) { - n := new(big.Int).Set(x) - z = big.NewInt(0) - - for i := 0; i < y.BitLen(); i++ { - if y.Bit(i) == 1 { - z = addMod(z, n, p) - } - n = addMod(n, n, p) - } - - return z -} - -// invMod computes z = (1/x) % p. -func invMod(x *big.Int, p *big.Int) (z *big.Int) { - z = new(big.Int).ModInverse(x, p) - return z -} - -// expMod computes z = (x^e) % p. -func expMod(x *big.Int, y *big.Int, p *big.Int) (z *big.Int) { - z = new(big.Int).Exp(x, y, p) - return z -} - -// sqrtMod computes z = sqrt(x) % p. -func sqrtMod(x *big.Int, p *big.Int) (z *big.Int) { - /* assert that p % 4 == 3 */ - if new(big.Int).Mod(p, big.NewInt(4)).Cmp(big.NewInt(3)) != 0 { - panic("p is not equal to 3 mod 4!") - } - - /* z = sqrt(x) % p = x^((p+1)/4) % p */ - - /* e = (p+1)/4 */ - e := new(big.Int).Add(p, big.NewInt(1)) - e = e.Rsh(e, 2) - - z = expMod(x, e, p) - return z -} - -/*** Point Arithmetic on Curve ***/ - -// IsInfinity checks if point P is infinity on EllipticCurve ec. -func (ec *Curve) IsInfinity(P Point) bool { - /* We use (nil,nil) to represent O, the point at infinity. */ - - if P.X == nil && P.Y == nil { - return true - } - - return false -} - -// IsOnCurve checks if point P is on EllipticCurve ec. -func (ec Curve) IsOnCurve(P1, P2 *big.Int) bool { - P := Point{P1, P2} - if ec.IsInfinity(P) { - return false - } - - /* y**2 = x**3 + a*x + b % p */ - lhs := mulMod(P.Y, P.Y, ec.P) - rhs := addMod( - addMod( - expMod(P.X, big.NewInt(3), ec.P), - mulMod(ec.A, P.X, ec.P), ec.P), - ec.B, ec.P) - - if lhs.Cmp(rhs) == 0 { - return true - } - - return false -} - -// Add computes R = P + Q on EllipticCurve ec. -func (ec Curve) Add(P1, P2, Q1, Q2 *big.Int) (R1 *big.Int, R2 *big.Int) { - /* See rules 1-5 on SEC1 pg.7 http://www.secg.org/collateral/sec1_final.pdf */ - P := Point{P1, P2} - Q := Point{Q1, Q2} - R := Point{} - if ec.IsInfinity(P) && ec.IsInfinity(Q) { - /* Rule #1 Identity */ - /* R = O + O = O */ - - R.X = nil - R.Y = nil - - } else if ec.IsInfinity(P) { - /* Rule #2 Identity */ - /* R = O + Q = Q */ - - R.X = new(big.Int).Set(Q.X) - R.Y = new(big.Int).Set(Q.Y) - - } else if ec.IsInfinity(Q) { - /* Rule #2 Identity */ - /* R = P + O = P */ - - R.X = new(big.Int).Set(P.X) - R.Y = new(big.Int).Set(P.Y) - - } else if P.X.Cmp(Q.X) == 0 && addMod(P.Y, Q.Y, ec.P).Sign() == 0 { - /* Rule #3 Identity */ - /* R = (x,y) + (x,-y) = O */ - - R.X = nil - R.Y = nil - - } else if P.X.Cmp(Q.X) == 0 && P.Y.Cmp(Q.Y) == 0 && P.Y.Sign() != 0 { - /* Rule #5 Point doubling */ - /* R = P + P */ - - /* Lambda = (3*P.X*P.X + a) / (2*P.Y) */ - num := addMod( - mulMod(big.NewInt(3), - mulMod(P.X, P.X, ec.P), ec.P), - ec.A, ec.P) - den := invMod(mulMod(big.NewInt(2), P.Y, ec.P), ec.P) - lambda := mulMod(num, den, ec.P) - - /* R.X = lambda*lambda - 2*P.X */ - R.X = subMod( - mulMod(lambda, lambda, ec.P), - mulMod(big.NewInt(2), P.X, ec.P), - ec.P) - /* R.Y = lambda*(P.X - R.X) - P.Y */ - R.Y = subMod( - mulMod(lambda, subMod(P.X, R.X, ec.P), ec.P), - P.Y, ec.P) - - } else if P.X.Cmp(Q.X) != 0 { - /* Rule #4 Point addition */ - /* R = P + Q */ - - /* Lambda = (Q.Y - P.Y) / (Q.X - P.X) */ - num := subMod(Q.Y, P.Y, ec.P) - den := invMod(subMod(Q.X, P.X, ec.P), ec.P) - lambda := mulMod(num, den, ec.P) - - /* R.X = lambda*lambda - P.X - Q.X */ - R.X = subMod( - subMod( - mulMod(lambda, lambda, ec.P), - P.X, ec.P), - Q.X, ec.P) - - /* R.Y = lambda*(P.X - R.X) - P.Y */ - R.Y = subMod( - mulMod(lambda, - subMod(P.X, R.X, ec.P), ec.P), - P.Y, ec.P) - } else { - panic(fmt.Sprintf("Unsupported point addition: %v + %v", P.format(), Q.format())) - } - - return R.X, R.Y -} - -// ScalarMult computes Q = k * P on EllipticCurve ec. -func (ec Curve) ScalarMult(P1, P2 *big.Int, l []byte) (Q1, Q2 *big.Int) { - /* Note: this function is not constant time, due to the branching nature of - * the underlying point Add() function. */ - - /* Montgomery Ladder Point Multiplication - * - * Implementation based on pseudocode here: - * See https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder */ - - P := Point{P1, P2} - k := big.Int{} - k.SetBytes(l) - - var R0 Point - var R1 Point - - R0.X = nil - R0.Y = nil - R1.X = new(big.Int).Set(P.X) - R1.Y = new(big.Int).Set(P.Y) - - for i := ec.N.BitLen() - 1; i >= 0; i-- { - if k.Bit(i) == 0 { - R1.X, R1.Y = ec.Add(R0.X, R0.Y, R1.X, R1.Y) - R0.X, R0.Y = ec.Add(R0.X, R0.Y, R0.X, R0.Y) - } else { - R0.X, R0.Y = ec.Add(R0.X, R0.Y, R1.X, R1.Y) - R1.X, R1.Y = ec.Add(R1.X, R1.Y, R1.X, R1.Y) - } - } - - return R0.X, R0.Y -} - -// ScalarBaseMult computes Q = k * G on EllipticCurve ec. -func (ec Curve) ScalarBaseMult(k []byte) (Q1, Q2 *big.Int) { - - return ec.ScalarMult(ec.G.X, ec.G.Y, k) -} - -// Decompress decompresses coordinate x and ylsb (y's least significant bit) into a Point P on EllipticCurve ec. -func (ec *Curve) Decompress(x *big.Int, ylsb uint) (P Point, err error) { - /* y**2 = x**3 + a*x + b % p */ - rhs := addMod( - addMod( - expMod(x, big.NewInt(3), ec.P), - mulMod(ec.A, x, ec.P), - ec.P), - ec.B, ec.P) - - /* y = sqrt(rhs) % p */ - y := sqrtMod(rhs, ec.P) - - /* Use -y if opposite lsb is required */ - if y.Bit(0) != (ylsb & 0x1) { - y = subMod(big.NewInt(0), y, ec.P) - } - - P.X = x - P.Y = y - - if !ec.IsOnCurve(P.X, P.Y) { - return P, errors.New("compressed (x, ylsb) not on curve") - } - - return P, nil -} - -// Double will return the (x1+x1,y1+y1) -func (ec Curve) Double(x1, y1 *big.Int) (x, y *big.Int) { - x = &big.Int{} - x.SetBytes([]byte{0x00}) - y = &big.Int{} - y.SetBytes([]byte{0x00}) - return x, y -} diff --git a/_pkg.dev/crypto/elliptic/elliptic_test.go b/_pkg.dev/crypto/elliptic/elliptic_test.go deleted file mode 100755 index fa83dd034..000000000 --- a/_pkg.dev/crypto/elliptic/elliptic_test.go +++ /dev/null @@ -1,231 +0,0 @@ -/* btckeygenie v1.0.0 - * https://github.com/vsergeev/btckeygenie - * License: MIT - */ - -package elliptic - -import ( - "encoding/hex" - "math/big" - "testing" -) - -func init() { - - curve = NewEllipticCurve(Secp256k1) -} - -func hex2int(hexstring string) (v *big.Int) { - v, _ = new(big.Int).SetString(hexstring, 16) - return v -} - -func TestOnCurve(t *testing.T) { - if !curve.IsOnCurve(curve.G.X, curve.G.Y) { - t.Fatal("failure G on curve") - } - - t.Log("G on curve") -} - -func TestInfinity(t *testing.T) { - O := Point{nil, nil} - - /* O not on curve */ - if curve.IsOnCurve(O.X, O.Y) { - t.Fatal("failure O on curve") - } - - /* O is infinity */ - if !curve.IsInfinity(O) { - t.Fatal("failure O not infinity on curve") - } - - t.Log("O is not on curve and is infinity") -} - -func TestPointAdd(t *testing.T) { - X := "50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352" - Y := "2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6" - - P := Point{hex2int(X), hex2int(Y)} - O := Point{nil, nil} - - /* R = O + O = O */ - { - R1, R2 := curve.Add(O.X, O.Y, O.X, O.Y) - R := Point{R1, R2} - if !curve.IsInfinity(R) { - t.Fatal("failure O + O = O") - } - t.Log("success O + O = O") - } - - /* R = P + O = P */ - { - R1, R2 := curve.Add(P.X, P.Y, O.X, O.Y) - R := Point{R1, R2} - if R.X.Cmp(P.X) != 0 || R.Y.Cmp(P.Y) != 0 { - t.Fatal("failure P + O = P") - } - t.Log("success P + O = P") - } - - /* R = O + Q = Q */ - { - R1, R2 := curve.Add(O.X, O.Y, P.X, P.Y) - R := Point{R1, R2} - if R.X.Cmp(P.X) != 0 || R.Y.Cmp(P.Y) != 0 { - t.Fatal("failure O + Q = Q") - } - t.Log("success O + Q = Q") - } - - /* R = (x,y) + (x,-y) = O */ - { - Q := Point{P.X, subMod(big.NewInt(0), P.Y, curve.P)} - - R1, R2 := curve.Add(P.X, P.Y, Q.X, Q.Y) - R := Point{R1, R2} - if !curve.IsInfinity(R) { - t.Fatal("failure (x,y) + (x,-y) = O") - } - t.Log("success (x,y) + (x,-y) = O") - } - - /* R = P + P */ - { - PP := Point{hex2int("5dbcd5dfea550eb4fd3b5333f533f086bb5267c776e2a1a9d8e84c16a6743d82"), hex2int("8dde3986b6cbe395da64b6e95fb81f8af73f6e0cf1100555005bb4ba2a6a4a07")} - - R1, R2 := curve.Add(P.X, P.Y, P.X, P.Y) - R := Point{R1, R2} - if R.X.Cmp(PP.X) != 0 || R.Y.Cmp(PP.Y) != 0 { - t.Fatal("failure P + P") - } - t.Log("success P + P") - } - - Q := Point{hex2int("a83b8de893467d3a88d959c0eb4032d9ce3bf80f175d4d9e75892a3ebb8ab7e5"), hex2int("370f723328c24b7a97fe34063ba68f253fb08f8645d7c8b9a4ff98e3c29e7f0d")} - PQ := Point{hex2int("fe7d540002e4355eb0ec36c217b4735495de7bd8634055ded3683b0e9da70ef1"), hex2int("fc033c1d74cb34e087a3495e505c0fc0e9e3e8297994878d89d882254ce8a9ef")} - - /* R = P + Q */ - { - R1, R2 := curve.Add(P.X, P.Y, Q.X, Q.Y) - R := Point{R1, R2} - if R.X.Cmp(PQ.X) != 0 || R.Y.Cmp(PQ.Y) != 0 { - t.Fatal("failure P + Q") - } - t.Log("success P + Q") - } - - /* R = Q + P */ - { - R1, R2 := curve.Add(Q.X, Q.Y, P.X, P.Y) - R := Point{R1, R2} - if R.X.Cmp(PQ.X) != 0 || R.Y.Cmp(PQ.Y) != 0 { - t.Fatal("failure Q + P") - } - t.Log("success Q + P") - } -} - -func TestPointScalarMult(t *testing.T) { - X := "50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352" - Y := "2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6" - P := Point{hex2int(X), hex2int(Y)} - - /* Q = k*P */ - { - T := Point{hex2int("87d592bfdd24adb52147fea343db93e10d0585bc66d91e365c359973c0dc7067"), hex2int("a374e206cb7c8cd1074bdf9bf6ddea135f983aaa6475c9ab3bb4c38a0046541b")} - input, _ := hex.DecodeString("14eb373700c3836404acd0820d9fa8dfa098d26177ca6e18b1c7f70c6af8fc18") - - Q1, Q2 := curve.ScalarMult(P.X, P.Y, input) - Q := Point{Q1, Q2} - if Q.X.Cmp(T.X) != 0 || Q.Y.Cmp(T.Y) != 0 { - t.Fatal("failure k*P") - } - t.Log("success k*P") - } - - /* Q = n*G = O */ - { - Q1, Q2 := curve.ScalarMult(curve.G.X, curve.G.Y, curve.N.Bytes()) - Q := Point{Q1, Q2} - if !curve.IsInfinity(Q) { - t.Fatal("failure n*G = O") - } - t.Log("success n*G = O") - } -} - -func TestPointScalarBaseMult(t *testing.T) { - /* Sample Private Key */ - D := "18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725" - /* Sample Corresponding Public Key */ - X := "50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352" - Y := "2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6" - - P := Point{hex2int(X), hex2int(Y)} - - /* Q = d*G = P */ - - Q1, Q2 := curve.ScalarBaseMult(hex2int(D).Bytes()) - Q := Point{Q1, Q2} - if P.X.Cmp(Q.X) != 0 || P.Y.Cmp(Q.Y) != 0 { - t.Fatal("failure Q = d*G") - } - t.Log("success Q = d*G") - - /* Q on curve */ - if !curve.IsOnCurve(Q.X, Q.Y) { - t.Fatal("failure Q on curve") - } - t.Log("success Q on curve") - - /* R = 0*G = O */ - R1, R2 := curve.ScalarBaseMult(big.NewInt(0).Bytes()) - R := Point{R1, R2} - if !curve.IsInfinity(R) { - t.Fatal("failure 0*G = O") - } - t.Log("success 0*G = O") -} - -func TestPointDecompress(t *testing.T) { - /* Valid points */ - var validDecompressVectors = []Point{ - {hex2int("50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"), hex2int("2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6")}, - {hex2int("a83b8de893467d3a88d959c0eb4032d9ce3bf80f175d4d9e75892a3ebb8ab7e5"), hex2int("370f723328c24b7a97fe34063ba68f253fb08f8645d7c8b9a4ff98e3c29e7f0d")}, - {hex2int("f680556678e25084a82fa39e1b1dfd0944f7e69fddaa4e03ce934bd6b291dca0"), hex2int("52c10b721d34447e173721fb0151c68de1106badb089fb661523b8302a9097f5")}, - {hex2int("241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f"), hex2int("513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d")}, - } - - for i := 0; i < len(validDecompressVectors); i++ { - P, err := curve.Decompress(validDecompressVectors[i].X, validDecompressVectors[i].Y.Bit(0)) - if err != nil { - t.Fatalf("failure decompress P, got error %v on index %d", err, i) - } - if P.X.Cmp(validDecompressVectors[i].X) != 0 || P.Y.Cmp(validDecompressVectors[i].Y) != 0 { - t.Fatalf("failure decompress P, got mismatch on index %d", i) - } - } - t.Log("success Decompress() on valid vectors") - - /* Invalid points */ - var invalidDecompressVectors = []struct { - X *big.Int - YLsb uint - }{ - {hex2int("c8e337cee51ae9af3c0ef923705a0cb1b76f7e8463b3d3060a1c8d795f9630fd"), 0}, - {hex2int("c8e337cee51ae9af3c0ef923705a0cb1b76f7e8463b3d3060a1c8d795f9630fd"), 1}, - } - - for i := 0; i < len(invalidDecompressVectors); i++ { - _, err := curve.Decompress(invalidDecompressVectors[i].X, invalidDecompressVectors[i].YLsb) - if err == nil { - t.Fatalf("failure decompress invalid P, got decompressed point on index %d", i) - } - } - t.Log("success Decompress() on invalid vectors") -} From b77e533d13a6f540c1f213bc81cea3d173c9201a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 27 Aug 2019 16:29:42 +0300 Subject: [PATCH 6/9] crypto/wallet: move public/private key into the new keys package And drop associated _pkg.dev remnants (refs. #307). Original `dev` branch had two separate packages for public and private keys, but those are so intertwined (`TestHelper` subpackage is a proof) that it's better unite them and all associated code (like WIF and NEP-2) in one package. This patch also: * creates internal `keytestcases` package to share things with wallet (maybe it'll be changed in some future) * ports some tests from `dev` * ports Verify() method for public key from `dev` * expands TestPrivateKey() with public key check --- _pkg.dev/crypto/privatekey/privatekey.go | 125 ------------- _pkg.dev/crypto/privatekey/privatekey_test.go | 48 ----- .../crypto/publickey/TestHelper/helper.go | 33 ---- .../publickey/TestHelper/helper_test.go | 34 ---- _pkg.dev/crypto/publickey/publickey.go | 164 ------------------ _pkg.dev/crypto/publickey/publickey_test.go | 81 --------- pkg/core/account_state.go | 10 +- pkg/core/account_state_test.go | 5 +- pkg/core/asset_state.go | 6 +- pkg/core/asset_state_test.go | 4 +- pkg/core/transaction/enrollment.go | 6 +- pkg/core/transaction/register.go | 6 +- pkg/core/transaction/register_test.go | 5 +- pkg/core/util.go | 14 +- pkg/core/validator_state.go | 6 +- pkg/{wallet => crypto/keys}/nep2.go | 9 +- pkg/{wallet => crypto/keys}/nep2_test.go | 22 +-- pkg/{wallet => crypto/keys}/private_key.go | 6 +- pkg/crypto/keys/private_key_test.go | 65 +++++++ .../{public_key.go => keys/publickey.go} | 32 +++- .../publickey_test.go} | 18 +- pkg/crypto/keys/sign_verify_test.go | 56 ++++++ pkg/{wallet => crypto/keys}/wif.go | 4 +- pkg/{wallet => crypto/keys}/wif_test.go | 2 +- pkg/internal/keytestcases/testcases.go | 37 ++++ pkg/rpc/client.go | 10 +- pkg/rpc/txBuilder.go | 4 +- pkg/rpc/txTypes.go | 4 +- pkg/rpc/wrappers/account_state.go | 4 +- pkg/smartcontract/contract.go | 4 +- pkg/smartcontract/contract_test.go | 10 +- pkg/wallet/account.go | 17 +- pkg/wallet/account_test.go | 24 +-- pkg/wallet/private_key_test.go | 74 -------- pkg/wallet/wallet.go | 6 +- 35 files changed, 298 insertions(+), 657 deletions(-) delete mode 100755 _pkg.dev/crypto/privatekey/privatekey.go delete mode 100755 _pkg.dev/crypto/privatekey/privatekey_test.go delete mode 100755 _pkg.dev/crypto/publickey/TestHelper/helper.go delete mode 100755 _pkg.dev/crypto/publickey/TestHelper/helper_test.go delete mode 100755 _pkg.dev/crypto/publickey/publickey.go delete mode 100755 _pkg.dev/crypto/publickey/publickey_test.go rename pkg/{wallet => crypto/keys}/nep2.go (97%) rename pkg/{wallet => crypto/keys}/nep2_test.go (52%) rename pkg/{wallet => crypto/keys}/private_key.go (97%) create mode 100644 pkg/crypto/keys/private_key_test.go rename pkg/crypto/{public_key.go => keys/publickey.go} (84%) rename pkg/crypto/{public_key_test.go => keys/publickey_test.go} (66%) create mode 100755 pkg/crypto/keys/sign_verify_test.go rename pkg/{wallet => crypto/keys}/wif.go (98%) rename pkg/{wallet => crypto/keys}/wif_test.go (99%) create mode 100644 pkg/internal/keytestcases/testcases.go delete mode 100644 pkg/wallet/private_key_test.go diff --git a/_pkg.dev/crypto/privatekey/privatekey.go b/_pkg.dev/crypto/privatekey/privatekey.go deleted file mode 100755 index 5749b41fd..000000000 --- a/_pkg.dev/crypto/privatekey/privatekey.go +++ /dev/null @@ -1,125 +0,0 @@ -package privatekey - -import ( - "bytes" - "crypto/rand" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "io" - "math/big" - - "github.com/CityOfZion/neo-go/pkg/crypto/publickey" - - "github.com/CityOfZion/neo-go/pkg/crypto/base58" - "github.com/CityOfZion/neo-go/pkg/crypto/elliptic" - "github.com/CityOfZion/neo-go/pkg/crypto/hash" - "github.com/nspcc-dev/rfc6979" -) - -// PrivateKey represents a NEO private key. -type PrivateKey struct { - b []byte -} - -// NewPrivateKey will create a new private key -// With curve as Secp256r1 -func NewPrivateKey() (*PrivateKey, error) { - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - b := make([]byte, curve.N.BitLen()/8+8) - if _, err := io.ReadFull(rand.Reader, b); err != nil { - return nil, err - } - - d := new(big.Int).SetBytes(b) - d.Mod(d, new(big.Int).Sub(curve.N, big.NewInt(1))) - d.Add(d, big.NewInt(1)) - - p := &PrivateKey{b: d.Bytes()} - return p, nil -} - -// NewPrivateKeyFromHex will create a new private key hex string -func NewPrivateKeyFromHex(str string) (*PrivateKey, error) { - b, err := hex.DecodeString(str) - if err != nil { - return nil, err - } - return NewPrivateKeyFromBytes(b) -} - -// NewPrivateKeyFromBytes returns a NEO PrivateKey from the given byte slice. -func NewPrivateKeyFromBytes(b []byte) (*PrivateKey, error) { - if len(b) != 32 { - return nil, fmt.Errorf( - "invalid byte length: expected %d bytes got %d", 32, len(b), - ) - } - return &PrivateKey{b}, nil -} - -// PublicKey returns a the public corresponding to the private key -// For the curve secp256r1 -func (p *PrivateKey) PublicKey() (*publickey.PublicKey, error) { - var ( - c = elliptic.NewEllipticCurve(elliptic.Secp256r1) - q = new(big.Int).SetBytes(p.b) - ) - - p1, p2 := c.ScalarBaseMult(q.Bytes()) - point := elliptic.Point{ - X: p1, - Y: p2, - } - if !c.IsOnCurve(p1, p2) { - return nil, errors.New("failed to derive public key using elliptic curve") - } - - return &publickey.PublicKey{ - Curve: c, - Point: point, - }, nil - -} - -// WIFEncode will converts a private key -// to the Wallet Import Format for NEO -func WIFEncode(key []byte) (s string) { - if len(key) != 32 { - return "invalid private key length" - } - - buf := new(bytes.Buffer) - buf.WriteByte(0x80) - buf.Write(key) - - buf.WriteByte(0x01) - - checksum, _ := hash.Checksum(buf.Bytes()) - - buf.Write(checksum) - - WIF := base58.Encode(buf.Bytes()) - return WIF -} - -// Sign will sign the corresponding data using the private key -func (p *PrivateKey) Sign(data []byte) ([]byte, error) { - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - key := p.b - digest, _ := hash.Sha256(data) - - r, s, err := rfc6979.SignECDSA(curve, key, digest[:], sha256.New) - if err != nil { - return nil, err - } - - curveOrderByteSize := curve.P.BitLen() / 8 - rBytes, sBytes := r.Bytes(), s.Bytes() - signature := make([]byte, curveOrderByteSize*2) - copy(signature[curveOrderByteSize-len(rBytes):], rBytes) - copy(signature[curveOrderByteSize*2-len(sBytes):], sBytes) - - return signature, nil -} diff --git a/_pkg.dev/crypto/privatekey/privatekey_test.go b/_pkg.dev/crypto/privatekey/privatekey_test.go deleted file mode 100755 index 7c46737b6..000000000 --- a/_pkg.dev/crypto/privatekey/privatekey_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package privatekey - -import ( - "encoding/hex" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPrivateKeyToPublicKey(t *testing.T) { - input := "495d528227c7dcc234c690af1222e67cde916dac1652cad97e0263825a8268a6" - - privateKey, err := NewPrivateKeyFromHex(input) - if err != nil { - t.Fatal(err) - } - pubKey, _ := privateKey.PublicKey() - pubKeyBytes := pubKey.Bytes() - actual := hex.EncodeToString(pubKeyBytes) - expected := "03cd4c4ee9c8e1fae9d12ecf7c96cb3a057b550393f9e82182c4dae1139871682e" - assert.Equal(t, expected, actual) -} -func TestWIFEncode(t *testing.T) { - input := "29bbf53185a973d2e3803cb92908fd08117486d1f2e7bab73ed0d00255511637" - inputBytes, _ := hex.DecodeString(input) - - actual := WIFEncode(inputBytes) - expected := "KxcqV28rGDcpVR3fYg7R9vricLpyZ8oZhopyFLAWuRv7Y8TE9WhW" - assert.Equal(t, expected, actual) -} - -func TestSigning(t *testing.T) { - // These were taken from the rfcPage:https://tools.ietf.org/html/rfc6979#page-33 - // public key: U = xG - //Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 - //Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 - PrivateKey, _ := NewPrivateKeyFromHex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721") - - data, err := PrivateKey.Sign([]byte("sample")) - if err != nil { - t.Fatal(err) - } - - r := "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716" - s := "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8" - assert.Equal(t, strings.ToLower(r+s), hex.EncodeToString(data)) -} diff --git a/_pkg.dev/crypto/publickey/TestHelper/helper.go b/_pkg.dev/crypto/publickey/TestHelper/helper.go deleted file mode 100755 index 248e27be8..000000000 --- a/_pkg.dev/crypto/publickey/TestHelper/helper.go +++ /dev/null @@ -1,33 +0,0 @@ -package pubkeytesthelper - -import ( - "github.com/CityOfZion/neo-go/pkg/crypto/hash" - "github.com/CityOfZion/neo-go/pkg/crypto/privatekey" -) - -// SignDataWithRandomPrivateKey will sign data with -// a random private key, then verify said data -// returning true if Verify returns true -func SignDataWithRandomPrivateKey(data []byte) (bool, error) { - - hashedData, err := hash.Sha256(data) - if err != nil { - return false, err - } - - privKey, err := privatekey.NewPrivateKey() - if err != nil { - return false, err - } - signedData, err := privKey.Sign(data) - if err != nil { - return false, err - } - pubKey, err := privKey.PublicKey() - if err != nil { - return false, err - } - result := pubKey.Verify(signedData, hashedData.Bytes()) - - return result, nil -} diff --git a/_pkg.dev/crypto/publickey/TestHelper/helper_test.go b/_pkg.dev/crypto/publickey/TestHelper/helper_test.go deleted file mode 100755 index 68f8c5047..000000000 --- a/_pkg.dev/crypto/publickey/TestHelper/helper_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package pubkeytesthelper - -import ( - "testing" - - "github.com/CityOfZion/neo-go/pkg/crypto/hash" - "github.com/CityOfZion/neo-go/pkg/crypto/privatekey" - "github.com/stretchr/testify/assert" -) - -func TestPubKeyVerify(t *testing.T) { - actual, err := SignDataWithRandomPrivateKey([]byte("sample")) - - if err != nil { - t.Fatal(err) - } - expected := true - - assert.Equal(t, expected, actual) -} - -func TestWrongPubKey(t *testing.T) { - privKey, _ := privatekey.NewPrivateKey() - sample := []byte("sample") - hashedData, _ := hash.Sha256(sample) - signedData, _ := privKey.Sign(sample) - - secondPrivKey, _ := privatekey.NewPrivateKey() - wrongPubKey, _ := secondPrivKey.PublicKey() - - actual := wrongPubKey.Verify(signedData, hashedData.Bytes()) - expcted := false - assert.Equal(t, expcted, actual) -} diff --git a/_pkg.dev/crypto/publickey/publickey.go b/_pkg.dev/crypto/publickey/publickey.go deleted file mode 100755 index 285914a44..000000000 --- a/_pkg.dev/crypto/publickey/publickey.go +++ /dev/null @@ -1,164 +0,0 @@ -package publickey - -import ( - "bytes" - "crypto/ecdsa" - "encoding/binary" - "encoding/hex" - "fmt" - "io" - "math/big" - - "github.com/CityOfZion/neo-go/pkg/crypto/base58" - "github.com/CityOfZion/neo-go/pkg/crypto/elliptic" - "github.com/CityOfZion/neo-go/pkg/crypto/hash" -) - -// PublicKeys is a list of public keys. -type PublicKeys []*PublicKey - -func (keys PublicKeys) Len() int { return len(keys) } -func (keys PublicKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] } -func (keys PublicKeys) Less(i, j int) bool { - - if keys[i].X.Cmp(keys[j].X) == -1 { - return true - } - if keys[i].X.Cmp(keys[j].X) == 1 { - return false - } - if keys[i].X.Cmp(keys[j].X) == 0 { - return false - } - - return keys[i].Y.Cmp(keys[j].Y) == -1 -} - -// PublicKey represents a public key and provides a high level -// API around the ECPoint. -type PublicKey struct { - Curve elliptic.Curve - elliptic.Point -} - -// NewPublicKeyFromString return a public key created from the -// given hex string. -func NewPublicKeyFromString(s string) (*PublicKey, error) { - b, err := hex.DecodeString(s) - if err != nil { - return nil, err - } - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - - pubKey := &PublicKey{curve, elliptic.Point{}} - - if err := pubKey.DecodeBinary(bytes.NewReader(b)); err != nil { - return nil, err - } - - return pubKey, nil -} - -// Bytes returns the byte array representation of the public key. -func (p *PublicKey) Bytes() []byte { - if p.Curve.IsInfinity(p.Point) { - return []byte{0x00} - } - - var ( - x = p.X.Bytes() - paddedX = append(bytes.Repeat([]byte{0x00}, 32-len(x)), x...) - prefix = byte(0x03) - ) - - if p.Y.Bit(0) == 0 { - prefix = byte(0x02) - } - - return append([]byte{prefix}, paddedX...) -} - -// ToAddress will convert a public key to it's neo-address -func (p *PublicKey) ToAddress() string { - - publicKeyBytes := p.Bytes() - - publicKeyBytes = append([]byte{0x21}, publicKeyBytes...) // 0x21 = length of pubKey - publicKeyBytes = append(publicKeyBytes, 0xAC) // 0xAC = CheckSig - - hash160PubKey, _ := hash.Hash160(publicKeyBytes) - - versionHash160PubKey := append([]byte{0x17}, hash160PubKey.Bytes()...) - - checksum, _ := hash.Checksum(versionHash160PubKey) - - checkVersionHash160 := append(versionHash160PubKey, checksum...) - - address := base58.Encode(checkVersionHash160) - - return address -} - -// DecodeBinary decodes a PublicKey from the given io.Reader. -func (p *PublicKey) DecodeBinary(r io.Reader) error { - - var prefix uint8 - if err := binary.Read(r, binary.LittleEndian, &prefix); err != nil { - return err - } - - // Infinity - if prefix == 0x00 { - p.Point = elliptic.Point{} - return nil - } - - // Compressed public keys. - if prefix == 0x02 || prefix == 0x03 { - - b := make([]byte, 32) - if err := binary.Read(r, binary.LittleEndian, b); err != nil { - return err - } - - var err error - - p.Point, err = p.Curve.Decompress(new(big.Int).SetBytes(b), uint(prefix&0x1)) - if err != nil { - return err - } - - } else if prefix == 0x04 { - buf := make([]byte, 65) - if err := binary.Read(r, binary.LittleEndian, buf); err != nil { - return err - } - p.X = new(big.Int).SetBytes(buf[1:33]) - p.Y = new(big.Int).SetBytes(buf[33:65]) - } else { - return fmt.Errorf("invalid prefix %d", prefix) - } - - return nil -} - -// EncodeBinary encodes a PublicKey to the given io.Writer. -func (p *PublicKey) EncodeBinary(w io.Writer) error { - return binary.Write(w, binary.LittleEndian, p.Bytes()) -} - -// Verify returns true if the signature is valid and corresponds -// to the hash and public key -func (p *PublicKey) Verify(signature []byte, hash []byte) bool { - - publicKey := &ecdsa.PublicKey{} - publicKey.Curve = p.Curve - publicKey.X = p.X - publicKey.Y = p.Y - if p.X == nil || p.Y == nil { - return false - } - rBytes := new(big.Int).SetBytes(signature[0:32]) - sBytes := new(big.Int).SetBytes(signature[32:64]) - return ecdsa.Verify(publicKey, hash, rBytes, sBytes) -} diff --git a/_pkg.dev/crypto/publickey/publickey_test.go b/_pkg.dev/crypto/publickey/publickey_test.go deleted file mode 100755 index 0f93adb0c..000000000 --- a/_pkg.dev/crypto/publickey/publickey_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package publickey - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "io" - "math/big" - "testing" - - "github.com/CityOfZion/neo-go/pkg/crypto/elliptic" - "github.com/stretchr/testify/assert" -) - -func TestDecodeFromString(t *testing.T) { - str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c" - pubKey, err := NewPublicKeyFromString(str) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, str, hex.EncodeToString(pubKey.Bytes())) -} - -func TestEncodeDecodeInfinity(t *testing.T) { - - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - - key := &PublicKey{curve, elliptic.Point{}} - buf := new(bytes.Buffer) - assert.Nil(t, key.EncodeBinary(buf)) - assert.Equal(t, 1, buf.Len()) - - keyDecode := &PublicKey{} - assert.Nil(t, keyDecode.DecodeBinary(buf)) - assert.Equal(t, []byte{0x00}, keyDecode.Bytes()) -} - -func TestEncodeDecodePublicKey(t *testing.T) { - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - - for i := 0; i < 4; i++ { - p := &PublicKey{curve, randomECPoint()} - buf := new(bytes.Buffer) - assert.Nil(t, p.EncodeBinary(buf)) - - pDecode := &PublicKey{curve, elliptic.Point{}} - assert.Nil(t, pDecode.DecodeBinary(buf)) - assert.Equal(t, p.X, pDecode.X) - } -} - -func TestPubkeyToAddress(t *testing.T) { - - pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4") - if err != nil { - t.Fatal(err) - } - - actual := pubKey.ToAddress() - expected := "AUpGsNCHzSimeMRVPQfhwrVdiUp8Q2N2Qx" - assert.Equal(t, expected, actual) -} - -func randomECPoint() elliptic.Point { - curve := elliptic.NewEllipticCurve(elliptic.Secp256r1) - b := make([]byte, curve.N.BitLen()/8+8) - if _, err := io.ReadFull(rand.Reader, b); err != nil { - return elliptic.Point{} - } - - d := new(big.Int).SetBytes(b) - d.Mod(d, new(big.Int).Sub(curve.N, big.NewInt(1))) - d.Add(d, big.NewInt(1)) - - q := new(big.Int).SetBytes(d.Bytes()) - P1, P2 := curve.ScalarBaseMult(q.Bytes()) - return elliptic.Point{ - X: P1, - Y: P2, - } -} diff --git a/pkg/core/account_state.go b/pkg/core/account_state.go index 7bc02817e..01fecc7a7 100644 --- a/pkg/core/account_state.go +++ b/pkg/core/account_state.go @@ -7,7 +7,7 @@ import ( "io" "github.com/CityOfZion/neo-go/pkg/core/storage" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -52,7 +52,7 @@ type AccountState struct { Version uint8 ScriptHash util.Uint160 IsFrozen bool - Votes []*crypto.PublicKey + Votes []*keys.PublicKey Balances map[util.Uint256]util.Fixed8 } @@ -62,7 +62,7 @@ func NewAccountState(scriptHash util.Uint160) *AccountState { Version: 0, ScriptHash: scriptHash, IsFrozen: false, - Votes: []*crypto.PublicKey{}, + Votes: []*keys.PublicKey{}, Balances: make(map[util.Uint256]util.Fixed8), } } @@ -80,9 +80,9 @@ func (s *AccountState) DecodeBinary(r io.Reader) error { } lenVotes := util.ReadVarUint(r) - s.Votes = make([]*crypto.PublicKey, lenVotes) + s.Votes = make([]*keys.PublicKey, lenVotes) for i := 0; i < int(lenVotes); i++ { - s.Votes[i] = &crypto.PublicKey{} + s.Votes[i] = &keys.PublicKey{} if err := s.Votes[i].DecodeBinary(r); err != nil { return err } diff --git a/pkg/core/account_state_test.go b/pkg/core/account_state_test.go index abce2daf9..ae157f07e 100644 --- a/pkg/core/account_state_test.go +++ b/pkg/core/account_state_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -13,11 +14,11 @@ func TestDecodeEncodeAccountState(t *testing.T) { var ( n = 10 balances = make(map[util.Uint256]util.Fixed8) - votes = make([]*crypto.PublicKey, n) + votes = make([]*keys.PublicKey, n) ) for i := 0; i < n; i++ { balances[randomUint256()] = util.Fixed8(int64(randomInt(1, 10000))) - votes[i] = &crypto.PublicKey{ + votes[i] = &keys.PublicKey{ ECPoint: crypto.RandomECPoint(), } } diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index 2bbfbf7b7..ee4b4407b 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -7,7 +7,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -39,7 +39,7 @@ type AssetState struct { Precision uint8 FeeMode uint8 FeeAddress util.Uint160 - Owner *crypto.PublicKey + Owner *keys.PublicKey Admin util.Uint160 Issuer util.Uint160 Expiration uint32 @@ -77,7 +77,7 @@ func (a *AssetState) DecodeBinary(r io.Reader) error { return err } - a.Owner = &crypto.PublicKey{} + a.Owner = &keys.PublicKey{} if err := a.Owner.DecodeBinary(r); err != nil { return err } diff --git a/pkg/core/asset_state_test.go b/pkg/core/asset_state_test.go index 37ca5eee4..952c81fc4 100644 --- a/pkg/core/asset_state_test.go +++ b/pkg/core/asset_state_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/CityOfZion/neo-go/pkg/core/transaction" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -19,7 +19,7 @@ func TestEncodeDecodeAssetState(t *testing.T) { Available: util.Fixed8(100), Precision: 0, FeeMode: feeMode, - Owner: &crypto.PublicKey{}, + Owner: &keys.PublicKey{}, Admin: randomUint160(), Issuer: randomUint160(), Expiration: 10, diff --git a/pkg/core/transaction/enrollment.go b/pkg/core/transaction/enrollment.go index f4295696d..e43b92481 100644 --- a/pkg/core/transaction/enrollment.go +++ b/pkg/core/transaction/enrollment.go @@ -3,7 +3,7 @@ package transaction import ( "io" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" ) // A Enrollment transaction represents an enrollment form, which indicates @@ -13,12 +13,12 @@ import ( // The way to cancel the registration is: Spend the deposit on the address of the PublicKey. type EnrollmentTX struct { // PublicKey of the validator - PublicKey *crypto.PublicKey + PublicKey *keys.PublicKey } // DecodeBinary implements the Payload interface. func (tx *EnrollmentTX) DecodeBinary(r io.Reader) error { - tx.PublicKey = &crypto.PublicKey{} + tx.PublicKey = &keys.PublicKey{} return tx.PublicKey.DecodeBinary(r) } diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 423c33e44..5f2467a47 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -4,7 +4,7 @@ import ( "encoding/binary" "io" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -25,7 +25,7 @@ type RegisterTX struct { Precision uint8 // Public key of the owner - Owner *crypto.PublicKey + Owner *keys.PublicKey Admin util.Uint160 } @@ -50,7 +50,7 @@ func (tx *RegisterTX) DecodeBinary(r io.Reader) error { return err } - tx.Owner = &crypto.PublicKey{} + tx.Owner = &keys.PublicKey{} if err := tx.Owner.DecodeBinary(r); err != nil { return err } diff --git a/pkg/core/transaction/register_test.go b/pkg/core/transaction/register_test.go index cbb48570c..710979e3e 100644 --- a/pkg/core/transaction/register_test.go +++ b/pkg/core/transaction/register_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -20,7 +21,7 @@ func TestRegisterTX(t *testing.T) { Name: "this is some token I created", Amount: util.Fixed8FromInt64(1000000), Precision: 8, - Owner: &crypto.PublicKey{}, + Owner: &keys.PublicKey{}, Admin: someuint160, }, } @@ -51,7 +52,7 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) { assert.Equal(t, "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]", txData.Name) assert.Equal(t, util.Fixed8FromInt64(100000000), txData.Amount) assert.Equal(t, uint8(0), txData.Precision) - assert.Equal(t, &crypto.PublicKey{}, txData.Owner) + assert.Equal(t, &keys.PublicKey{}, txData.Owner) assert.Equal(t, "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt", crypto.AddressFromUint160(txData.Admin)) assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString()) diff --git a/pkg/core/util.go b/pkg/core/util.go index 8ee050185..de359a38f 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -8,8 +8,8 @@ import ( "github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" - "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" @@ -101,7 +101,7 @@ func governingTokenTX() *transaction.Transaction { Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]", Amount: util.Fixed8FromInt64(100000000), Precision: 0, - Owner: &crypto.PublicKey{}, + Owner: &keys.PublicKey{}, Admin: admin, } @@ -124,7 +124,7 @@ func utilityTokenTX() *transaction.Transaction { Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]", Amount: calculateUtilityAmount(), Precision: 8, - Owner: &crypto.PublicKey{}, + Owner: &keys.PublicKey{}, Admin: admin, } tx := &transaction.Transaction{ @@ -139,10 +139,10 @@ func utilityTokenTX() *transaction.Transaction { return tx } -func getValidators(cfg config.ProtocolConfiguration) ([]*crypto.PublicKey, error) { - validators := make([]*crypto.PublicKey, len(cfg.StandbyValidators)) +func getValidators(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) { + validators := make([]*keys.PublicKey, len(cfg.StandbyValidators)) for i, pubKeyStr := range cfg.StandbyValidators { - pubKey, err := crypto.NewPublicKeyFromString(pubKeyStr) + pubKey, err := keys.NewPublicKeyFromString(pubKeyStr) if err != nil { return nil, err } @@ -151,7 +151,7 @@ func getValidators(cfg config.ProtocolConfiguration) ([]*crypto.PublicKey, error return validators, nil } -func getNextConsensusAddress(validators []*crypto.PublicKey) (val util.Uint160, err error) { +func getNextConsensusAddress(validators []*keys.PublicKey) (val util.Uint160, err error) { vlen := len(validators) raw, err := smartcontract.CreateMultiSigRedeemScript( vlen-(vlen-1)/3, diff --git a/pkg/core/validator_state.go b/pkg/core/validator_state.go index f63bf2acf..b93585e99 100644 --- a/pkg/core/validator_state.go +++ b/pkg/core/validator_state.go @@ -1,16 +1,16 @@ package core import ( - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) // Validators is a mapping between public keys and ValidatorState. -type Validators map[*crypto.PublicKey]*ValidatorState +type Validators map[*keys.PublicKey]*ValidatorState // ValidatorState holds the state of a validator. type ValidatorState struct { - PublicKey *crypto.PublicKey + PublicKey *keys.PublicKey Registered bool Votes util.Fixed8 } diff --git a/pkg/wallet/nep2.go b/pkg/crypto/keys/nep2.go similarity index 97% rename from pkg/wallet/nep2.go rename to pkg/crypto/keys/nep2.go index df43bf38c..10a73576f 100644 --- a/pkg/wallet/nep2.go +++ b/pkg/crypto/keys/nep2.go @@ -1,4 +1,4 @@ -package wallet +package keys import ( "bytes" @@ -24,20 +24,21 @@ const ( var nepHeader = []byte{0x01, 0x42} -type scryptParams struct { +type ScryptParams struct { N int `json:"n"` R int `json:"r"` P int `json:"p"` } -func newScryptParams() scryptParams { - return scryptParams{ +func NEP2ScryptParams() ScryptParams { + return ScryptParams{ N: n, R: r, P: p, } } + // NEP2Encrypt encrypts a the PrivateKey using a given passphrase // under the NEP-2 standard. func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) { diff --git a/pkg/wallet/nep2_test.go b/pkg/crypto/keys/nep2_test.go similarity index 52% rename from pkg/wallet/nep2_test.go rename to pkg/crypto/keys/nep2_test.go index cbf6a0e6e..e5162e1d4 100644 --- a/pkg/wallet/nep2_test.go +++ b/pkg/crypto/keys/nep2_test.go @@ -1,32 +1,34 @@ -package wallet +package keys import ( "testing" + + "github.com/CityOfZion/neo-go/pkg/internal/keytestcases" ) func TestNEP2Encrypt(t *testing.T) { - for _, testCase := range testKeyCases { + for _, testCase := range keytestcases.Arr { - privKey, err := NewPrivateKeyFromHex(testCase.privateKey) + privKey, err := NewPrivateKeyFromHex(testCase.PrivateKey) if err != nil { t.Fatal(err) } - encryptedWif, err := NEP2Encrypt(privKey, testCase.passphrase) + encryptedWif, err := NEP2Encrypt(privKey, testCase.Passphrase) if err != nil { t.Fatal(err) } - if want, have := testCase.encryptedWif, encryptedWif; want != have { + if want, have := testCase.EncryptedWif, encryptedWif; want != have { t.Fatalf("expected %s got %s", want, have) } } } func TestNEP2Decrypt(t *testing.T) { - for _, testCase := range testKeyCases { + for _, testCase := range keytestcases.Arr { - privKeyString, err := NEP2Decrypt(testCase.encryptedWif, testCase.passphrase) + privKeyString, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase) if err != nil { t.Fatal(err) @@ -37,7 +39,7 @@ func TestNEP2Decrypt(t *testing.T) { t.Fatal(err) } - if want, have := testCase.privateKey, privKey.String(); want != have { + if want, have := testCase.PrivateKey, privKey.String(); want != have { t.Fatalf("expected %s got %s", want, have) } @@ -45,7 +47,7 @@ func TestNEP2Decrypt(t *testing.T) { if err != nil { t.Fatal(err) } - if want, have := testCase.wif, wif; want != have { + if want, have := testCase.Wif, wif; want != have { t.Fatalf("expected %s got %s", want, have) } @@ -53,7 +55,7 @@ func TestNEP2Decrypt(t *testing.T) { if err != nil { t.Fatal(err) } - if want, have := testCase.address, address; want != have { + if want, have := testCase.Address, address; want != have { t.Fatalf("expected %s got %s", want, have) } } diff --git a/pkg/wallet/private_key.go b/pkg/crypto/keys/private_key.go similarity index 97% rename from pkg/wallet/private_key.go rename to pkg/crypto/keys/private_key.go index 883da1ee4..ae173b279 100644 --- a/pkg/wallet/private_key.go +++ b/pkg/crypto/keys/private_key.go @@ -1,4 +1,4 @@ -package wallet +package keys import ( "bytes" @@ -67,10 +67,10 @@ func NewPrivateKeyFromRawBytes(b []byte) (*PrivateKey, error) { } // PublicKey derives the public key from the private key. -func (p *PrivateKey) PublicKey() (*crypto.PublicKey, error) { +func (p *PrivateKey) PublicKey() (*PublicKey, error) { var ( err error - pk crypto.PublicKey + pk PublicKey c = crypto.NewEllipticCurve() q = new(big.Int).SetBytes(p.b) ) diff --git a/pkg/crypto/keys/private_key_test.go b/pkg/crypto/keys/private_key_test.go new file mode 100644 index 000000000..f5289acbc --- /dev/null +++ b/pkg/crypto/keys/private_key_test.go @@ -0,0 +1,65 @@ +package keys + +import ( + "encoding/hex" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/CityOfZion/neo-go/pkg/internal/keytestcases" +) + + +func TestPrivateKey(t *testing.T) { + for _, testCase := range keytestcases.Arr { + privKey, err := NewPrivateKeyFromHex(testCase.PrivateKey) + if err != nil { + t.Fatal(err) + } + address, err := privKey.Address() + if err != nil { + t.Fatal(err) + } + if want, have := testCase.Address, address; want != have { + t.Fatalf("expected %s got %s", want, have) + } + wif, err := privKey.WIF() + if err != nil { + t.Fatal(err) + } + if want, have := testCase.Wif, wif; want != have { + t.Fatalf("expected %s got %s", want, have) + } + pubKey, _ := privKey.PublicKey() + assert.Equal(t, hex.EncodeToString(pubKey.Bytes()), testCase.PublicKey) + } +} + +func TestPrivateKeyFromWIF(t *testing.T) { + for _, testCase := range keytestcases.Arr { + key, err := NewPrivateKeyFromWIF(testCase.Wif) + if err != nil { + t.Fatal(err) + } + if want, have := testCase.PrivateKey, key.String(); want != have { + t.Fatalf("expected %s got %s", want, have) + } + } +} + +func TestSigning(t *testing.T) { + // These were taken from the rfcPage:https://tools.ietf.org/html/rfc6979#page-33 + // public key: U = xG + //Ux = 60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6 + //Uy = 7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299 + PrivateKey, _ := NewPrivateKeyFromHex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721") + + data, err := PrivateKey.Sign([]byte("sample")) + if err != nil { + t.Fatal(err) + } + + r := "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716" + s := "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8" + assert.Equal(t, strings.ToLower(r+s), hex.EncodeToString(data)) +} diff --git a/pkg/crypto/public_key.go b/pkg/crypto/keys/publickey.go similarity index 84% rename from pkg/crypto/public_key.go rename to pkg/crypto/keys/publickey.go index 4eb2c8b55..12e5ee167 100644 --- a/pkg/crypto/public_key.go +++ b/pkg/crypto/keys/publickey.go @@ -1,8 +1,9 @@ -package crypto +package keys import ( "bytes" "crypto/ecdsa" + "crypto/elliptic" "crypto/x509" "encoding/binary" "encoding/hex" @@ -10,6 +11,7 @@ import ( "math/big" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/pkg/errors" ) @@ -35,7 +37,7 @@ func (keys PublicKeys) Less(i, j int) bool { // PublicKey represents a public key and provides a high level // API around the ECPoint. type PublicKey struct { - ECPoint + crypto.ECPoint } // NewPublicKeyFromString return a public key created from the @@ -87,7 +89,7 @@ func NewPublicKeyFromRawBytes(data []byte) (*PublicKey, error) { return nil, errors.New("given bytes aren't ECDSA public key") } key := PublicKey{ - ECPoint{ + crypto.ECPoint{ X: pk.X, Y: pk.Y, }, @@ -102,14 +104,14 @@ func (p *PublicKey) DecodeBytes(data []byte) error { switch prefix := data[0]; prefix { // Infinity case 0x00: - p.ECPoint = ECPoint{} + p.ECPoint = crypto.ECPoint{} // Compressed public keys case 0x02, 0x03: if l < 33 { return errors.Errorf("bad binary size(%d)", l) } - c := NewEllipticCurve() + c := crypto.NewEllipticCurve() var err error p.ECPoint, err = c.Decompress(new(big.Int).SetBytes(data[1:]), uint(prefix&0x1)) if err != nil { @@ -139,7 +141,7 @@ func (p *PublicKey) DecodeBinary(r io.Reader) error { // Infinity switch prefix { case 0x00: - p.ECPoint = ECPoint{} + p.ECPoint = crypto.ECPoint{} return nil // Compressed public keys case 0x02, 0x03: @@ -190,6 +192,22 @@ func (p *PublicKey) Address() (string, error) { csum := hash.Checksum(b) b = append(b, csum...) - address := Base58Encode(b) + address := crypto.Base58Encode(b) return address, nil } + +// Verify returns true if the signature is valid and corresponds +// to the hash and public key +func (p *PublicKey) Verify(signature []byte, hash []byte) bool { + + publicKey := &ecdsa.PublicKey{} + publicKey.Curve = elliptic.P256() + publicKey.X = p.X + publicKey.Y = p.Y + if p.X == nil || p.Y == nil { + return false + } + rBytes := new(big.Int).SetBytes(signature[0:32]) + sBytes := new(big.Int).SetBytes(signature[32:64]) + return ecdsa.Verify(publicKey, hash, rBytes, sBytes) +} diff --git a/pkg/crypto/public_key_test.go b/pkg/crypto/keys/publickey_test.go similarity index 66% rename from pkg/crypto/public_key_test.go rename to pkg/crypto/keys/publickey_test.go index 99c809c1b..da2e5c5cd 100644 --- a/pkg/crypto/public_key_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -1,15 +1,16 @@ -package crypto +package keys import ( "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/stretchr/testify/assert" ) func TestEncodeDecodeInfinity(t *testing.T) { - key := &PublicKey{ECPoint{}} + key := &PublicKey{crypto.ECPoint{}} buf := new(bytes.Buffer) assert.Nil(t, key.EncodeBinary(buf)) assert.Equal(t, 1, buf.Len()) @@ -21,7 +22,7 @@ func TestEncodeDecodeInfinity(t *testing.T) { func TestEncodeDecodePublicKey(t *testing.T) { for i := 0; i < 4; i++ { - p := &PublicKey{RandomECPoint()} + p := &PublicKey{crypto.RandomECPoint()} buf := new(bytes.Buffer) assert.Nil(t, p.EncodeBinary(buf)) @@ -39,3 +40,14 @@ func TestDecodeFromString(t *testing.T) { } assert.Equal(t, str, hex.EncodeToString(pubKey.Bytes())) } + +func TestPubkeyToAddress(t *testing.T) { + pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4") + if err != nil { + t.Fatal(err) + } + + actual, _ := pubKey.Address() + expected := "AUpGsNCHzSimeMRVPQfhwrVdiUp8Q2N2Qx" + assert.Equal(t, expected, actual) +} diff --git a/pkg/crypto/keys/sign_verify_test.go b/pkg/crypto/keys/sign_verify_test.go new file mode 100755 index 000000000..5a8e11c64 --- /dev/null +++ b/pkg/crypto/keys/sign_verify_test.go @@ -0,0 +1,56 @@ +package keys + +import ( + "testing" + + "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/stretchr/testify/assert" +) + +// SignDataWithRandomPrivateKey will sign data with +// a random private key, then verify said data +// returning true if Verify returns true +func SignDataWithRandomPrivateKey(data []byte) (bool, error) { + hashedData := hash.Sha256(data) + + privKey, err := NewPrivateKey() + if err != nil { + return false, err + } + signedData, err := privKey.Sign(data) + if err != nil { + return false, err + } + pubKey, err := privKey.PublicKey() + if err != nil { + return false, err + } + result := pubKey.Verify(signedData, hashedData.Bytes()) + + return result, nil +} + +func TestPubKeyVerify(t *testing.T) { + actual, err := SignDataWithRandomPrivateKey([]byte("sample")) + + if err != nil { + t.Fatal(err) + } + expected := true + + assert.Equal(t, expected, actual) +} + +func TestWrongPubKey(t *testing.T) { + privKey, _ := NewPrivateKey() + sample := []byte("sample") + hashedData := hash.Sha256(sample) + signedData, _ := privKey.Sign(sample) + + secondPrivKey, _ := NewPrivateKey() + wrongPubKey, _ := secondPrivKey.PublicKey() + + actual := wrongPubKey.Verify(signedData, hashedData.Bytes()) + expcted := false + assert.Equal(t, expcted, actual) +} diff --git a/pkg/wallet/wif.go b/pkg/crypto/keys/wif.go similarity index 98% rename from pkg/wallet/wif.go rename to pkg/crypto/keys/wif.go index 8147a97fa..874774a91 100644 --- a/pkg/wallet/wif.go +++ b/pkg/crypto/keys/wif.go @@ -1,4 +1,4 @@ -package wallet +package keys import ( "bytes" @@ -98,7 +98,7 @@ func (wif WIF) GetVerificationScript() ([]byte, error) { ) var ( vScript []byte - pubkey *crypto.PublicKey + pubkey *PublicKey ) pubkey, err := wif.PrivateKey.PublicKey() if err != nil { diff --git a/pkg/wallet/wif_test.go b/pkg/crypto/keys/wif_test.go similarity index 99% rename from pkg/wallet/wif_test.go rename to pkg/crypto/keys/wif_test.go index 2705147b0..5113f7a93 100644 --- a/pkg/wallet/wif_test.go +++ b/pkg/crypto/keys/wif_test.go @@ -1,4 +1,4 @@ -package wallet +package keys import ( "encoding/hex" diff --git a/pkg/internal/keytestcases/testcases.go b/pkg/internal/keytestcases/testcases.go new file mode 100644 index 000000000..b2fd83366 --- /dev/null +++ b/pkg/internal/keytestcases/testcases.go @@ -0,0 +1,37 @@ +package keytestcases + +type Ktype struct { + Address, + PrivateKey, + PublicKey, + Wif, + Passphrase, + EncryptedWif string +} + +var Arr = []Ktype{ + { + Address: "ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW", + PrivateKey: "7d128a6d096f0c14c3a25a2b0c41cf79661bfcb4a8cc95aaaea28bde4d732344", + PublicKey: "02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef", + Wif: "L1QqQJnpBwbsPGAuutuzPTac8piqvbR1HRjrY5qHup48TBCBFe4g", + Passphrase: "city of zion", + EncryptedWif: "6PYLHmDf6AjF4AsVtosmxHuPYeuyJL3SLuw7J1U8i7HxKAnYNsp61HYRfF", + }, + { + Address: "ALfnhLg7rUyL6Jr98bzzoxz5J7m64fbR4s", + PrivateKey: "9ab7e154840daca3a2efadaf0df93cd3a5b51768c632f5433f86909d9b994a69", + PublicKey: "031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9", + Wif: "L2QTooFoDFyRFTxmtiVHt5CfsXfVnexdbENGDkkrrgTTryiLsPMG", + Passphrase: "我的密码", + EncryptedWif: "6PYWVp3xfgvnuNKP7ZavSViYvvim2zuzx9Q33vuWZr8aURiKeJ6Zm7BfPQ", + }, + { + Address: "AVf4UGKevVrMR1j3UkPsuoYKSC4ocoAkKx", + PrivateKey: "3edee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915b", + PublicKey: "02232ce8d2e2063dce0451131851d47421bfc4fc1da4db116fca5302c0756462fa", + Wif: "KyKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiG", + Passphrase: "MyL33tP@33w0rd", + EncryptedWif: "6PYNoc1EG5J38MTqGN9Anphfdd6UwbS4cpFCzHhrkSKBBbV1qkbJJZQnkn", + }, +} diff --git a/pkg/rpc/client.go b/pkg/rpc/client.go index 2df32a43f..e21b4ef6a 100644 --- a/pkg/rpc/client.go +++ b/pkg/rpc/client.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/CityOfZion/neo-go/pkg/wallet" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/pkg/errors" ) @@ -32,7 +32,7 @@ type Client struct { ctx context.Context version string wifMu *sync.Mutex - wif *wallet.WIF + wif *keys.WIF balancerMu *sync.Mutex balancer BalanceGetter } @@ -93,10 +93,10 @@ func NewClient(ctx context.Context, endpoint string, opts ClientOptions) (*Clien }, nil } -func (c *Client) WIF() wallet.WIF { +func (c *Client) WIF() keys.WIF { c.wifMu.Lock() defer c.wifMu.Unlock() - return wallet.WIF{ + return keys.WIF{ Version: c.wif.Version, Compressed: c.wif.Compressed, PrivateKey: c.wif.PrivateKey, @@ -109,7 +109,7 @@ func (c *Client) WIF() wallet.WIF { func (c *Client) SetWIF(wif string) error { c.wifMu.Lock() defer c.wifMu.Unlock() - decodedWif, err := wallet.WIFDecode(wif, 0x00) + decodedWif, err := keys.WIFDecode(wif, 0x00) if err != nil { return errors.Wrap(err, "Failed to decode WIF; failed to add WIF to client ") } diff --git a/pkg/rpc/txBuilder.go b/pkg/rpc/txBuilder.go index 1d7f4dc46..eaf55f294 100644 --- a/pkg/rpc/txBuilder.go +++ b/pkg/rpc/txBuilder.go @@ -5,8 +5,8 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" - "github.com/CityOfZion/neo-go/pkg/wallet" errs "github.com/pkg/errors" ) @@ -67,7 +67,7 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac return tx, nil } -func GetInvocationScript(tx *transaction.Transaction, wif wallet.WIF) ([]byte, error) { +func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, error) { const ( pushbytes64 = 0x40 ) diff --git a/pkg/rpc/txTypes.go b/pkg/rpc/txTypes.go index ae4fead70..584d968cf 100644 --- a/pkg/rpc/txTypes.go +++ b/pkg/rpc/txTypes.go @@ -8,7 +8,7 @@ package rpc import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/util" - "github.com/CityOfZion/neo-go/pkg/wallet" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" ) type ( @@ -19,7 +19,7 @@ type ( assetId util.Uint256 address string value util.Fixed8 - wif wallet.WIF // a WIF to send the transaction + wif keys.WIF // a WIF to send the transaction // since there are many ways to provide unspents, // transaction composer stays agnostic to that how // unspents was got; diff --git a/pkg/rpc/wrappers/account_state.go b/pkg/rpc/wrappers/account_state.go index 8d6ab755e..dda35ac70 100644 --- a/pkg/rpc/wrappers/account_state.go +++ b/pkg/rpc/wrappers/account_state.go @@ -5,7 +5,7 @@ import ( "sort" "github.com/CityOfZion/neo-go/pkg/core" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -15,7 +15,7 @@ type AccountState struct { Version uint8 `json:"version"` ScriptHash util.Uint160 `json:"script_hash"` IsFrozen bool `json:"frozen"` - Votes []*crypto.PublicKey `json:"votes"` + Votes []*keys.PublicKey `json:"votes"` Balances []Balance `json:"balances"` } diff --git a/pkg/smartcontract/contract.go b/pkg/smartcontract/contract.go index 33214000f..7e978bfd3 100644 --- a/pkg/smartcontract/contract.go +++ b/pkg/smartcontract/contract.go @@ -5,12 +5,12 @@ import ( "fmt" "sort" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/vm" ) // CreateMultiSigRedeemScript will create a script runnable by the VM. -func CreateMultiSigRedeemScript(m int, publicKeys crypto.PublicKeys) ([]byte, error) { +func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, error) { if m <= 1 { return nil, fmt.Errorf("param m cannot be smaller or equal to 1 got %d", m) } diff --git a/pkg/smartcontract/contract_test.go b/pkg/smartcontract/contract_test.go index 3e1c4dcf9..2708e4f0a 100644 --- a/pkg/smartcontract/contract_test.go +++ b/pkg/smartcontract/contract_test.go @@ -4,18 +4,18 @@ import ( "bytes" "testing" - "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" "github.com/stretchr/testify/assert" ) func TestCreateMultiSigRedeemScript(t *testing.T) { - val1, _ := crypto.NewPublicKeyFromString("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c") - val2, _ := crypto.NewPublicKeyFromString("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093") - val3, _ := crypto.NewPublicKeyFromString("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a") + val1, _ := keys.NewPublicKeyFromString("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c") + val2, _ := keys.NewPublicKeyFromString("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093") + val3, _ := keys.NewPublicKeyFromString("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a") - validators := []*crypto.PublicKey{val1, val2, val3} + validators := []*keys.PublicKey{val1, val2, val3} out, err := CreateMultiSigRedeemScript(3, validators) if err != nil { diff --git a/pkg/wallet/account.go b/pkg/wallet/account.go index 5b186fb57..401665b65 100644 --- a/pkg/wallet/account.go +++ b/pkg/wallet/account.go @@ -1,12 +1,15 @@ package wallet -import "github.com/CityOfZion/neo-go/pkg/util" +import ( + "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/crypto/keys" +) // Account represents a NEO account. It holds the private and public key // along with some metadata. type Account struct { // NEO private key. - privateKey *PrivateKey + privateKey *keys.PrivateKey // NEO public key. publicKey []byte @@ -50,7 +53,7 @@ type Contract struct { // NewAccount creates a new Account with a random generated PrivateKey. func NewAccount() (*Account, error) { - priv, err := NewPrivateKey() + priv, err := keys.NewPrivateKey() if err != nil { return nil, err } @@ -60,7 +63,7 @@ func NewAccount() (*Account, error) { // DecryptAccount decrypt the encryptedWIF with the given passphrase and // return the decrypted Account. func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) { - wif, err := NEP2Decrypt(encryptedWIF, passphrase) + wif, err := keys.NEP2Decrypt(encryptedWIF, passphrase) if err != nil { return nil, err } @@ -70,7 +73,7 @@ func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) { // Encrypt encrypts the wallet's PrivateKey with the given passphrase // under the NEP-2 standard. func (a *Account) Encrypt(passphrase string) error { - wif, err := NEP2Encrypt(a.privateKey, passphrase) + wif, err := keys.NEP2Encrypt(a.privateKey, passphrase) if err != nil { return err } @@ -80,7 +83,7 @@ func (a *Account) Encrypt(passphrase string) error { // NewAccountFromWIF creates a new Account from the given WIF. func NewAccountFromWIF(wif string) (*Account, error) { - privKey, err := NewPrivateKeyFromWIF(wif) + privKey, err := keys.NewPrivateKeyFromWIF(wif) if err != nil { return nil, err } @@ -88,7 +91,7 @@ func NewAccountFromWIF(wif string) (*Account, error) { } // newAccountFromPrivateKey created a wallet from the given PrivateKey. -func newAccountFromPrivateKey(p *PrivateKey) (*Account, error) { +func newAccountFromPrivateKey(p *keys.PrivateKey) (*Account, error) { pubKey, err := p.PublicKey() if err != nil { return nil, err diff --git a/pkg/wallet/account_test.go b/pkg/wallet/account_test.go index 1c04ad9a2..cc46f1557 100644 --- a/pkg/wallet/account_test.go +++ b/pkg/wallet/account_test.go @@ -3,11 +3,13 @@ package wallet import ( "encoding/hex" "testing" + + "github.com/CityOfZion/neo-go/pkg/internal/keytestcases" ) func TestNewAccount(t *testing.T) { - for _, testCase := range testKeyCases { - acc, err := NewAccountFromWIF(testCase.wif) + for _, testCase := range keytestcases.Arr { + acc, err := NewAccountFromWIF(testCase.Wif) if err != nil { t.Fatal(err) } @@ -16,8 +18,8 @@ func TestNewAccount(t *testing.T) { } func TestDecryptAccount(t *testing.T) { - for _, testCase := range testKeyCases { - acc, err := DecryptAccount(testCase.encryptedWif, testCase.passphrase) + for _, testCase := range keytestcases.Arr { + acc, err := DecryptAccount(testCase.EncryptedWif, testCase.Passphrase) if err != nil { t.Fatal(err) } @@ -26,8 +28,8 @@ func TestDecryptAccount(t *testing.T) { } func TestNewFromWif(t *testing.T) { - for _, testCase := range testKeyCases { - acc, err := NewAccountFromWIF(testCase.wif) + for _, testCase := range keytestcases.Arr { + acc, err := NewAccountFromWIF(testCase.Wif) if err != nil { t.Fatal(err) } @@ -35,17 +37,17 @@ func TestNewFromWif(t *testing.T) { } } -func compareFields(t *testing.T, tk testKey, acc *Account) { - if want, have := tk.address, acc.Address; want != have { +func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) { + if want, have := tk.Address, acc.Address; want != have { t.Fatalf("expected %s got %s", want, have) } - if want, have := tk.wif, acc.wif; want != have { + if want, have := tk.Wif, acc.wif; want != have { t.Fatalf("expected %s got %s", want, have) } - if want, have := tk.publicKey, hex.EncodeToString(acc.publicKey); want != have { + if want, have := tk.PublicKey, hex.EncodeToString(acc.publicKey); want != have { t.Fatalf("expected %s got %s", want, have) } - if want, have := tk.privateKey, acc.privateKey.String(); want != have { + if want, have := tk.PrivateKey, acc.privateKey.String(); want != have { t.Fatalf("expected %s got %s", want, have) } } diff --git a/pkg/wallet/private_key_test.go b/pkg/wallet/private_key_test.go deleted file mode 100644 index 1c3961a94..000000000 --- a/pkg/wallet/private_key_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package wallet - -import "testing" - -type testKey struct { - address, - privateKey, - publicKey, - wif, - passphrase, - encryptedWif string -} - -var testKeyCases = []testKey{ - { - address: "ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW", - privateKey: "7d128a6d096f0c14c3a25a2b0c41cf79661bfcb4a8cc95aaaea28bde4d732344", - publicKey: "02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef", - wif: "L1QqQJnpBwbsPGAuutuzPTac8piqvbR1HRjrY5qHup48TBCBFe4g", - passphrase: "city of zion", - encryptedWif: "6PYLHmDf6AjF4AsVtosmxHuPYeuyJL3SLuw7J1U8i7HxKAnYNsp61HYRfF", - }, - { - address: "ALfnhLg7rUyL6Jr98bzzoxz5J7m64fbR4s", - privateKey: "9ab7e154840daca3a2efadaf0df93cd3a5b51768c632f5433f86909d9b994a69", - publicKey: "031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9", - wif: "L2QTooFoDFyRFTxmtiVHt5CfsXfVnexdbENGDkkrrgTTryiLsPMG", - passphrase: "我的密码", - encryptedWif: "6PYWVp3xfgvnuNKP7ZavSViYvvim2zuzx9Q33vuWZr8aURiKeJ6Zm7BfPQ", - }, - { - address: "AVf4UGKevVrMR1j3UkPsuoYKSC4ocoAkKx", - privateKey: "3edee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915b", - publicKey: "02232ce8d2e2063dce0451131851d47421bfc4fc1da4db116fca5302c0756462fa", - wif: "KyKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiG", - passphrase: "MyL33tP@33w0rd", - encryptedWif: "6PYNoc1EG5J38MTqGN9Anphfdd6UwbS4cpFCzHhrkSKBBbV1qkbJJZQnkn", - }, -} - -func TestPrivateKey(t *testing.T) { - for _, testCase := range testKeyCases { - privKey, err := NewPrivateKeyFromHex(testCase.privateKey) - if err != nil { - t.Fatal(err) - } - address, err := privKey.Address() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.address, address; want != have { - t.Fatalf("expected %s got %s", want, have) - } - wif, err := privKey.WIF() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.wif, wif; want != have { - t.Fatalf("expected %s got %s", want, have) - } - } -} - -func TestPrivateKeyFromWIF(t *testing.T) { - for _, testCase := range testKeyCases { - key, err := NewPrivateKeyFromWIF(testCase.wif) - if err != nil { - t.Fatal(err) - } - if want, have := testCase.privateKey, key.String(); want != have { - t.Fatalf("expected %s got %s", want, have) - } - } -} diff --git a/pkg/wallet/wallet.go b/pkg/wallet/wallet.go index eb990e306..691eca18c 100644 --- a/pkg/wallet/wallet.go +++ b/pkg/wallet/wallet.go @@ -4,6 +4,8 @@ import ( "encoding/json" "io" "os" + + "github.com/CityOfZion/neo-go/pkg/crypto/keys" ) const ( @@ -20,7 +22,7 @@ type Wallet struct { // in the wallet. Accounts []*Account `json:"accounts"` - Scrypt scryptParams `json:"scrypt"` + Scrypt keys.ScryptParams `json:"scrypt"` // Extra metadata can be used for storing arbitrary data. // This field can be empty. @@ -66,7 +68,7 @@ func newWallet(rw io.ReadWriter) *Wallet { return &Wallet{ Version: walletVersion, Accounts: []*Account{}, - Scrypt: newScryptParams(), + Scrypt: keys.NEP2ScryptParams(), rw: rw, path: path, } From 483b875f4a49d14477d7179f2ab24fbbff336181 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 27 Aug 2019 17:06:32 +0300 Subject: [PATCH 7/9] keys: simplify tests with assert package --- pkg/crypto/keys/nep2_test.go | 42 ++++++++--------------------- pkg/crypto/keys/private_key_test.go | 33 +++++++---------------- pkg/crypto/keys/publickey_test.go | 9 ++----- pkg/crypto/keys/sign_verify_test.go | 31 +++++---------------- pkg/crypto/keys/wif_test.go | 30 +++++++-------------- 5 files changed, 37 insertions(+), 108 deletions(-) diff --git a/pkg/crypto/keys/nep2_test.go b/pkg/crypto/keys/nep2_test.go index e5162e1d4..e3a7a1ebc 100644 --- a/pkg/crypto/keys/nep2_test.go +++ b/pkg/crypto/keys/nep2_test.go @@ -4,24 +4,19 @@ import ( "testing" "github.com/CityOfZion/neo-go/pkg/internal/keytestcases" + "github.com/stretchr/testify/assert" ) func TestNEP2Encrypt(t *testing.T) { for _, testCase := range keytestcases.Arr { privKey, err := NewPrivateKeyFromHex(testCase.PrivateKey) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) encryptedWif, err := NEP2Encrypt(privKey, testCase.Passphrase) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) - if want, have := testCase.EncryptedWif, encryptedWif; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Equal(t, testCase.EncryptedWif, encryptedWif) } } @@ -29,34 +24,19 @@ func TestNEP2Decrypt(t *testing.T) { for _, testCase := range keytestcases.Arr { privKeyString, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase) - - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) privKey, err := NewPrivateKeyFromWIF(privKeyString) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) - if want, have := testCase.PrivateKey, privKey.String(); want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Equal(t, testCase.PrivateKey, privKey.String()) wif, err := privKey.WIF() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.Wif, wif; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.Wif, wif) address, err := privKey.Address() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.Address, address; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.Address, address) } } diff --git a/pkg/crypto/keys/private_key_test.go b/pkg/crypto/keys/private_key_test.go index f5289acbc..dc45ef547 100644 --- a/pkg/crypto/keys/private_key_test.go +++ b/pkg/crypto/keys/private_key_test.go @@ -13,23 +13,14 @@ import ( func TestPrivateKey(t *testing.T) { for _, testCase := range keytestcases.Arr { privKey, err := NewPrivateKeyFromHex(testCase.PrivateKey) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) address, err := privKey.Address() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.Address, address; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.Address, address) + wif, err := privKey.WIF() - if err != nil { - t.Fatal(err) - } - if want, have := testCase.Wif, wif; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.Wif, wif) pubKey, _ := privKey.PublicKey() assert.Equal(t, hex.EncodeToString(pubKey.Bytes()), testCase.PublicKey) } @@ -38,12 +29,8 @@ func TestPrivateKey(t *testing.T) { func TestPrivateKeyFromWIF(t *testing.T) { for _, testCase := range keytestcases.Arr { key, err := NewPrivateKeyFromWIF(testCase.Wif) - if err != nil { - t.Fatal(err) - } - if want, have := testCase.PrivateKey, key.String(); want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.PrivateKey, key.String()) } } @@ -55,9 +42,7 @@ func TestSigning(t *testing.T) { PrivateKey, _ := NewPrivateKeyFromHex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721") data, err := PrivateKey.Sign([]byte("sample")) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) r := "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716" s := "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8" diff --git a/pkg/crypto/keys/publickey_test.go b/pkg/crypto/keys/publickey_test.go index da2e5c5cd..5ff9e5597 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -35,18 +35,13 @@ func TestEncodeDecodePublicKey(t *testing.T) { func TestDecodeFromString(t *testing.T) { str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c" pubKey, err := NewPublicKeyFromString(str) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) assert.Equal(t, str, hex.EncodeToString(pubKey.Bytes())) } func TestPubkeyToAddress(t *testing.T) { pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4") - if err != nil { - t.Fatal(err) - } - + assert.Nil(t, err) actual, _ := pubKey.Address() expected := "AUpGsNCHzSimeMRVPQfhwrVdiUp8Q2N2Qx" assert.Equal(t, expected, actual) diff --git a/pkg/crypto/keys/sign_verify_test.go b/pkg/crypto/keys/sign_verify_test.go index 5a8e11c64..3eb5c1b8e 100755 --- a/pkg/crypto/keys/sign_verify_test.go +++ b/pkg/crypto/keys/sign_verify_test.go @@ -7,38 +7,19 @@ import ( "github.com/stretchr/testify/assert" ) -// SignDataWithRandomPrivateKey will sign data with -// a random private key, then verify said data -// returning true if Verify returns true -func SignDataWithRandomPrivateKey(data []byte) (bool, error) { +func TestPubKeyVerify(t *testing.T) { + var data = []byte("sample") hashedData := hash.Sha256(data) privKey, err := NewPrivateKey() - if err != nil { - return false, err - } + assert.Nil(t, err) signedData, err := privKey.Sign(data) - if err != nil { - return false, err - } + assert.Nil(t, err) pubKey, err := privKey.PublicKey() - if err != nil { - return false, err - } + assert.Nil(t, err) result := pubKey.Verify(signedData, hashedData.Bytes()) - - return result, nil -} - -func TestPubKeyVerify(t *testing.T) { - actual, err := SignDataWithRandomPrivateKey([]byte("sample")) - - if err != nil { - t.Fatal(err) - } expected := true - - assert.Equal(t, expected, actual) + assert.Equal(t, expected, result) } func TestWrongPubKey(t *testing.T) { diff --git a/pkg/crypto/keys/wif_test.go b/pkg/crypto/keys/wif_test.go index 5113f7a93..cccc20949 100644 --- a/pkg/crypto/keys/wif_test.go +++ b/pkg/crypto/keys/wif_test.go @@ -3,6 +3,8 @@ package keys import ( "encoding/hex" "testing" + + "github.com/stretchr/testify/assert" ) type wifTestCase struct { @@ -36,29 +38,15 @@ var wifTestCases = []wifTestCase{ func TestWIFEncodeDecode(t *testing.T) { for _, testCase := range wifTestCases { b, err := hex.DecodeString(testCase.privateKey) - if err != nil { - t.Fatal(err) - } + assert.Nil(t, err) wif, err := WIFEncode(b, testCase.version, testCase.compressed) - if err != nil { - t.Fatal(err) - } - if want, have := testCase.wif, wif; want != have { - t.Fatalf("expected %s got %s", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.wif, wif) WIF, err := WIFDecode(wif, testCase.version) - if err != nil { - t.Fatal(err) - } - if want, have := testCase.privateKey, WIF.PrivateKey.String(); want != have { - t.Fatalf("expected %s got %s", want, have) - } - if want, have := testCase.compressed, WIF.Compressed; want != have { - t.Fatalf("expected %v got %v", want, have) - } - if want, have := testCase.version, WIF.Version; want != have { - t.Fatalf("expected %d got %d", want, have) - } + assert.Nil(t, err) + assert.Equal(t, testCase.privateKey, WIF.PrivateKey.String()) + assert.Equal(t, testCase.compressed, WIF.Compressed) + assert.Equal(t, testCase.version, WIF.Version) } } From 5836ae68736858e564557e353f65b3dfea8ce3d6 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 27 Aug 2019 17:16:33 +0300 Subject: [PATCH 8/9] keys: change Signature() and Address() to not return errors As they never can return any real one. --- pkg/crypto/keys/private_key.go | 4 ++-- pkg/crypto/keys/publickey.go | 17 +++++------------ pkg/crypto/keys/publickey_test.go | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/pkg/crypto/keys/private_key.go b/pkg/crypto/keys/private_key.go index ae173b279..4f975d2b0 100644 --- a/pkg/crypto/keys/private_key.go +++ b/pkg/crypto/keys/private_key.go @@ -125,7 +125,7 @@ func (p *PrivateKey) Address() (string, error) { if err != nil { return "", err } - return pk.Address() + return pk.Address(), nil } // Signature creates the signature using the private key. @@ -134,7 +134,7 @@ func (p *PrivateKey) Signature() ([]byte, error) { if err != nil { return nil, err } - return pk.Signature() + return pk.Signature(), nil } // Sign signs arbitrary length data using the private key. diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index 12e5ee167..ae2b14adf 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -168,32 +168,25 @@ func (p *PublicKey) EncodeBinary(w io.Writer) error { return binary.Write(w, binary.LittleEndian, p.Bytes()) } -func (p *PublicKey) Signature() ([]byte, error) { +func (p *PublicKey) Signature() []byte { b := p.Bytes() b = append([]byte{0x21}, b...) b = append(b, 0xAC) sig := hash.Hash160(b) - return sig.Bytes(), nil + return sig.Bytes() } -func (p *PublicKey) Address() (string, error) { - var ( - err error - b []byte - ) - if b, err = p.Signature(); err != nil { - return "", err - } +func (p *PublicKey) Address() string { + var b []byte = p.Signature() b = append([]byte{0x17}, b...) - csum := hash.Checksum(b) b = append(b, csum...) address := crypto.Base58Encode(b) - return address, nil + return address } // Verify returns true if the signature is valid and corresponds diff --git a/pkg/crypto/keys/publickey_test.go b/pkg/crypto/keys/publickey_test.go index 5ff9e5597..cddd76c5d 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -42,7 +42,7 @@ func TestDecodeFromString(t *testing.T) { func TestPubkeyToAddress(t *testing.T) { pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4") assert.Nil(t, err) - actual, _ := pubKey.Address() + actual := pubKey.Address() expected := "AUpGsNCHzSimeMRVPQfhwrVdiUp8Q2N2Qx" assert.Equal(t, expected, actual) } From 2a8e42060821c45bd4a1d2fd04bae2f1ca390232 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 27 Aug 2019 17:47:07 +0300 Subject: [PATCH 9/9] nep2: fix comment, NEP-2 is about keys, not wallets --- pkg/crypto/keys/nep2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/crypto/keys/nep2.go b/pkg/crypto/keys/nep2.go index 10a73576f..1dcde69ef 100644 --- a/pkg/crypto/keys/nep2.go +++ b/pkg/crypto/keys/nep2.go @@ -11,7 +11,7 @@ import ( "golang.org/x/text/unicode/norm" ) -// NEP-2 standard implementation for encrypting and decrypting wallets. +// NEP-2 standard implementation for encrypting and decrypting private keys. // NEP-2 specified parameters used for cryptography. const (