forked from TrueCloudLab/neoneo-go
Merge pull request #318 from nspcc-dev/drop-redundant-dev-code-part-2
Drop redundant dev code part 2, refs. #307.
This commit is contained in:
commit
2cb9a4a251
45 changed files with 299 additions and 1486 deletions
|
@ -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.
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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")
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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])
|
|
||||||
}
|
|
|
@ -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])
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"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"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ type AccountState struct {
|
||||||
Version uint8
|
Version uint8
|
||||||
ScriptHash util.Uint160
|
ScriptHash util.Uint160
|
||||||
IsFrozen bool
|
IsFrozen bool
|
||||||
Votes []*crypto.PublicKey
|
Votes []*keys.PublicKey
|
||||||
Balances map[util.Uint256]util.Fixed8
|
Balances map[util.Uint256]util.Fixed8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func NewAccountState(scriptHash util.Uint160) *AccountState {
|
||||||
Version: 0,
|
Version: 0,
|
||||||
ScriptHash: scriptHash,
|
ScriptHash: scriptHash,
|
||||||
IsFrozen: false,
|
IsFrozen: false,
|
||||||
Votes: []*crypto.PublicKey{},
|
Votes: []*keys.PublicKey{},
|
||||||
Balances: make(map[util.Uint256]util.Fixed8),
|
Balances: make(map[util.Uint256]util.Fixed8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,9 +80,9 @@ func (s *AccountState) DecodeBinary(r io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
lenVotes := util.ReadVarUint(r)
|
lenVotes := util.ReadVarUint(r)
|
||||||
s.Votes = make([]*crypto.PublicKey, lenVotes)
|
s.Votes = make([]*keys.PublicKey, lenVotes)
|
||||||
for i := 0; i < int(lenVotes); i++ {
|
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 {
|
if err := s.Votes[i].DecodeBinary(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"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/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -13,11 +14,11 @@ func TestDecodeEncodeAccountState(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
n = 10
|
n = 10
|
||||||
balances = make(map[util.Uint256]util.Fixed8)
|
balances = make(map[util.Uint256]util.Fixed8)
|
||||||
votes = make([]*crypto.PublicKey, n)
|
votes = make([]*keys.PublicKey, n)
|
||||||
)
|
)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
balances[randomUint256()] = util.Fixed8(int64(randomInt(1, 10000)))
|
balances[randomUint256()] = util.Fixed8(int64(randomInt(1, 10000)))
|
||||||
votes[i] = &crypto.PublicKey{
|
votes[i] = &keys.PublicKey{
|
||||||
ECPoint: crypto.RandomECPoint(),
|
ECPoint: crypto.RandomECPoint(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"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/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ type AssetState struct {
|
||||||
Precision uint8
|
Precision uint8
|
||||||
FeeMode uint8
|
FeeMode uint8
|
||||||
FeeAddress util.Uint160
|
FeeAddress util.Uint160
|
||||||
Owner *crypto.PublicKey
|
Owner *keys.PublicKey
|
||||||
Admin util.Uint160
|
Admin util.Uint160
|
||||||
Issuer util.Uint160
|
Issuer util.Uint160
|
||||||
Expiration uint32
|
Expiration uint32
|
||||||
|
@ -77,7 +77,7 @@ func (a *AssetState) DecodeBinary(r io.Reader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Owner = &crypto.PublicKey{}
|
a.Owner = &keys.PublicKey{}
|
||||||
if err := a.Owner.DecodeBinary(r); err != nil {
|
if err := a.Owner.DecodeBinary(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"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/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,7 @@ func TestEncodeDecodeAssetState(t *testing.T) {
|
||||||
Available: util.Fixed8(100),
|
Available: util.Fixed8(100),
|
||||||
Precision: 0,
|
Precision: 0,
|
||||||
FeeMode: feeMode,
|
FeeMode: feeMode,
|
||||||
Owner: &crypto.PublicKey{},
|
Owner: &keys.PublicKey{},
|
||||||
Admin: randomUint160(),
|
Admin: randomUint160(),
|
||||||
Issuer: randomUint160(),
|
Issuer: randomUint160(),
|
||||||
Expiration: 10,
|
Expiration: 10,
|
||||||
|
|
|
@ -3,7 +3,7 @@ package transaction
|
||||||
import (
|
import (
|
||||||
"io"
|
"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
|
// 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.
|
// The way to cancel the registration is: Spend the deposit on the address of the PublicKey.
|
||||||
type EnrollmentTX struct {
|
type EnrollmentTX struct {
|
||||||
// PublicKey of the validator
|
// PublicKey of the validator
|
||||||
PublicKey *crypto.PublicKey
|
PublicKey *keys.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements the Payload interface.
|
// DecodeBinary implements the Payload interface.
|
||||||
func (tx *EnrollmentTX) DecodeBinary(r io.Reader) error {
|
func (tx *EnrollmentTX) DecodeBinary(r io.Reader) error {
|
||||||
tx.PublicKey = &crypto.PublicKey{}
|
tx.PublicKey = &keys.PublicKey{}
|
||||||
return tx.PublicKey.DecodeBinary(r)
|
return tx.PublicKey.DecodeBinary(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"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/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ type RegisterTX struct {
|
||||||
Precision uint8
|
Precision uint8
|
||||||
|
|
||||||
// Public key of the owner
|
// Public key of the owner
|
||||||
Owner *crypto.PublicKey
|
Owner *keys.PublicKey
|
||||||
|
|
||||||
Admin util.Uint160
|
Admin util.Uint160
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func (tx *RegisterTX) DecodeBinary(r io.Reader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.Owner = &crypto.PublicKey{}
|
tx.Owner = &keys.PublicKey{}
|
||||||
if err := tx.Owner.DecodeBinary(r); err != nil {
|
if err := tx.Owner.DecodeBinary(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"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/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +21,7 @@ func TestRegisterTX(t *testing.T) {
|
||||||
Name: "this is some token I created",
|
Name: "this is some token I created",
|
||||||
Amount: util.Fixed8FromInt64(1000000),
|
Amount: util.Fixed8FromInt64(1000000),
|
||||||
Precision: 8,
|
Precision: 8,
|
||||||
Owner: &crypto.PublicKey{},
|
Owner: &keys.PublicKey{},
|
||||||
Admin: someuint160,
|
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, "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]", txData.Name)
|
||||||
assert.Equal(t, util.Fixed8FromInt64(100000000), txData.Amount)
|
assert.Equal(t, util.Fixed8FromInt64(100000000), txData.Amount)
|
||||||
assert.Equal(t, uint8(0), txData.Precision)
|
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, "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt", crypto.AddressFromUint160(txData.Admin))
|
||||||
assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString())
|
assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString())
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"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/hash"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
|
@ -101,7 +101,7 @@ func governingTokenTX() *transaction.Transaction {
|
||||||
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
|
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
|
||||||
Amount: util.Fixed8FromInt64(100000000),
|
Amount: util.Fixed8FromInt64(100000000),
|
||||||
Precision: 0,
|
Precision: 0,
|
||||||
Owner: &crypto.PublicKey{},
|
Owner: &keys.PublicKey{},
|
||||||
Admin: admin,
|
Admin: admin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ func utilityTokenTX() *transaction.Transaction {
|
||||||
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",
|
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",
|
||||||
Amount: calculateUtilityAmount(),
|
Amount: calculateUtilityAmount(),
|
||||||
Precision: 8,
|
Precision: 8,
|
||||||
Owner: &crypto.PublicKey{},
|
Owner: &keys.PublicKey{},
|
||||||
Admin: admin,
|
Admin: admin,
|
||||||
}
|
}
|
||||||
tx := &transaction.Transaction{
|
tx := &transaction.Transaction{
|
||||||
|
@ -139,10 +139,10 @@ func utilityTokenTX() *transaction.Transaction {
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValidators(cfg config.ProtocolConfiguration) ([]*crypto.PublicKey, error) {
|
func getValidators(cfg config.ProtocolConfiguration) ([]*keys.PublicKey, error) {
|
||||||
validators := make([]*crypto.PublicKey, len(cfg.StandbyValidators))
|
validators := make([]*keys.PublicKey, len(cfg.StandbyValidators))
|
||||||
for i, pubKeyStr := range cfg.StandbyValidators {
|
for i, pubKeyStr := range cfg.StandbyValidators {
|
||||||
pubKey, err := crypto.NewPublicKeyFromString(pubKeyStr)
|
pubKey, err := keys.NewPublicKeyFromString(pubKeyStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ func getValidators(cfg config.ProtocolConfiguration) ([]*crypto.PublicKey, error
|
||||||
return validators, nil
|
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)
|
vlen := len(validators)
|
||||||
raw, err := smartcontract.CreateMultiSigRedeemScript(
|
raw, err := smartcontract.CreateMultiSigRedeemScript(
|
||||||
vlen-(vlen-1)/3,
|
vlen-(vlen-1)/3,
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validators is a mapping between public keys and ValidatorState.
|
// 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.
|
// ValidatorState holds the state of a validator.
|
||||||
type ValidatorState struct {
|
type ValidatorState struct {
|
||||||
PublicKey *crypto.PublicKey
|
PublicKey *keys.PublicKey
|
||||||
Registered bool
|
Registered bool
|
||||||
Votes util.Fixed8
|
Votes util.Fixed8
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUint160DecodeAddress(t *testing.T) {
|
func TestUint160DecodeEncodeAddress(t *testing.T) {
|
||||||
addrs := []string{
|
addrs := []string{
|
||||||
"AMLr1CpPQtbEdiJdriX1HpRNMZUwbU2Huj",
|
"AMLr1CpPQtbEdiJdriX1HpRNMZUwbU2Huj",
|
||||||
"AKtwd3DRXj3nL5kHMUoNsdnsCEVjnuuTFF",
|
"AKtwd3DRXj3nL5kHMUoNsdnsCEVjnuuTFF",
|
||||||
|
@ -20,3 +20,15 @@ func TestUint160DecodeAddress(t *testing.T) {
|
||||||
assert.Equal(t, addr, AddressFromUint160(val))
|
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())
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package wallet
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -11,7 +11,7 @@ import (
|
||||||
"golang.org/x/text/unicode/norm"
|
"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.
|
// NEP-2 specified parameters used for cryptography.
|
||||||
const (
|
const (
|
||||||
|
@ -24,20 +24,21 @@ const (
|
||||||
|
|
||||||
var nepHeader = []byte{0x01, 0x42}
|
var nepHeader = []byte{0x01, 0x42}
|
||||||
|
|
||||||
type scryptParams struct {
|
type ScryptParams struct {
|
||||||
N int `json:"n"`
|
N int `json:"n"`
|
||||||
R int `json:"r"`
|
R int `json:"r"`
|
||||||
P int `json:"p"`
|
P int `json:"p"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newScryptParams() scryptParams {
|
func NEP2ScryptParams() ScryptParams {
|
||||||
return scryptParams{
|
return ScryptParams{
|
||||||
N: n,
|
N: n,
|
||||||
R: r,
|
R: r,
|
||||||
P: p,
|
P: p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NEP2Encrypt encrypts a the PrivateKey using a given passphrase
|
// NEP2Encrypt encrypts a the PrivateKey using a given passphrase
|
||||||
// under the NEP-2 standard.
|
// under the NEP-2 standard.
|
||||||
func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) {
|
func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) {
|
42
pkg/crypto/keys/nep2_test.go
Normal file
42
pkg/crypto/keys/nep2_test.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package keys
|
||||||
|
|
||||||
|
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)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
encryptedWif, err := NEP2Encrypt(privKey, testCase.Passphrase)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.EncryptedWif, encryptedWif)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNEP2Decrypt(t *testing.T) {
|
||||||
|
for _, testCase := range keytestcases.Arr {
|
||||||
|
|
||||||
|
privKeyString, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
privKey, err := NewPrivateKeyFromWIF(privKeyString)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.PrivateKey, privKey.String())
|
||||||
|
|
||||||
|
wif, err := privKey.WIF()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, testCase.Wif, wif)
|
||||||
|
|
||||||
|
address, err := privKey.Address()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, testCase.Address, address)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package wallet
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -67,10 +67,10 @@ func NewPrivateKeyFromRawBytes(b []byte) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKey derives the public key from the private key.
|
// PublicKey derives the public key from the private key.
|
||||||
func (p *PrivateKey) PublicKey() (*crypto.PublicKey, error) {
|
func (p *PrivateKey) PublicKey() (*PublicKey, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
pk crypto.PublicKey
|
pk PublicKey
|
||||||
c = crypto.NewEllipticCurve()
|
c = crypto.NewEllipticCurve()
|
||||||
q = new(big.Int).SetBytes(p.b)
|
q = new(big.Int).SetBytes(p.b)
|
||||||
)
|
)
|
||||||
|
@ -125,7 +125,7 @@ func (p *PrivateKey) Address() (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return pk.Address()
|
return pk.Address(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature creates the signature using the private key.
|
// Signature creates the signature using the private key.
|
||||||
|
@ -134,7 +134,7 @@ func (p *PrivateKey) Signature() ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pk.Signature()
|
return pk.Signature(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs arbitrary length data using the private key.
|
// Sign signs arbitrary length data using the private key.
|
50
pkg/crypto/keys/private_key_test.go
Normal file
50
pkg/crypto/keys/private_key_test.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
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)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
address, err := privKey.Address()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, testCase.Address, address)
|
||||||
|
|
||||||
|
wif, err := privKey.WIF()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, testCase.Wif, wif)
|
||||||
|
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)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, testCase.PrivateKey, key.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
r := "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716"
|
||||||
|
s := "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"
|
||||||
|
assert.Equal(t, strings.ToLower(r+s), hex.EncodeToString(data))
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
package crypto
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -10,6 +11,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto"
|
||||||
"github.com/pkg/errors"
|
"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
|
// PublicKey represents a public key and provides a high level
|
||||||
// API around the ECPoint.
|
// API around the ECPoint.
|
||||||
type PublicKey struct {
|
type PublicKey struct {
|
||||||
ECPoint
|
crypto.ECPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicKeyFromString return a public key created from the
|
// 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")
|
return nil, errors.New("given bytes aren't ECDSA public key")
|
||||||
}
|
}
|
||||||
key := PublicKey{
|
key := PublicKey{
|
||||||
ECPoint{
|
crypto.ECPoint{
|
||||||
X: pk.X,
|
X: pk.X,
|
||||||
Y: pk.Y,
|
Y: pk.Y,
|
||||||
},
|
},
|
||||||
|
@ -102,14 +104,14 @@ func (p *PublicKey) DecodeBytes(data []byte) error {
|
||||||
switch prefix := data[0]; prefix {
|
switch prefix := data[0]; prefix {
|
||||||
// Infinity
|
// Infinity
|
||||||
case 0x00:
|
case 0x00:
|
||||||
p.ECPoint = ECPoint{}
|
p.ECPoint = crypto.ECPoint{}
|
||||||
// Compressed public keys
|
// Compressed public keys
|
||||||
case 0x02, 0x03:
|
case 0x02, 0x03:
|
||||||
if l < 33 {
|
if l < 33 {
|
||||||
return errors.Errorf("bad binary size(%d)", l)
|
return errors.Errorf("bad binary size(%d)", l)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := NewEllipticCurve()
|
c := crypto.NewEllipticCurve()
|
||||||
var err error
|
var err error
|
||||||
p.ECPoint, err = c.Decompress(new(big.Int).SetBytes(data[1:]), uint(prefix&0x1))
|
p.ECPoint, err = c.Decompress(new(big.Int).SetBytes(data[1:]), uint(prefix&0x1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -139,7 +141,7 @@ func (p *PublicKey) DecodeBinary(r io.Reader) error {
|
||||||
// Infinity
|
// Infinity
|
||||||
switch prefix {
|
switch prefix {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
p.ECPoint = ECPoint{}
|
p.ECPoint = crypto.ECPoint{}
|
||||||
return nil
|
return nil
|
||||||
// Compressed public keys
|
// Compressed public keys
|
||||||
case 0x02, 0x03:
|
case 0x02, 0x03:
|
||||||
|
@ -166,30 +168,39 @@ func (p *PublicKey) EncodeBinary(w io.Writer) error {
|
||||||
return binary.Write(w, binary.LittleEndian, p.Bytes())
|
return binary.Write(w, binary.LittleEndian, p.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) Signature() ([]byte, error) {
|
func (p *PublicKey) Signature() []byte {
|
||||||
b := p.Bytes()
|
b := p.Bytes()
|
||||||
b = append([]byte{0x21}, b...)
|
b = append([]byte{0x21}, b...)
|
||||||
b = append(b, 0xAC)
|
b = append(b, 0xAC)
|
||||||
|
|
||||||
sig := hash.Hash160(b)
|
sig := hash.Hash160(b)
|
||||||
|
|
||||||
return sig.Bytes(), nil
|
return sig.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) Address() (string, error) {
|
func (p *PublicKey) Address() string {
|
||||||
var (
|
var b []byte = p.Signature()
|
||||||
err error
|
|
||||||
b []byte
|
|
||||||
)
|
|
||||||
if b, err = p.Signature(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
b = append([]byte{0x17}, b...)
|
b = append([]byte{0x17}, b...)
|
||||||
|
|
||||||
csum := hash.Checksum(b)
|
csum := hash.Checksum(b)
|
||||||
b = append(b, csum...)
|
b = append(b, csum...)
|
||||||
|
|
||||||
address := Base58Encode(b)
|
address := crypto.Base58Encode(b)
|
||||||
return address, nil
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
}
|
}
|
|
@ -1,15 +1,16 @@
|
||||||
package crypto
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeDecodeInfinity(t *testing.T) {
|
func TestEncodeDecodeInfinity(t *testing.T) {
|
||||||
key := &PublicKey{ECPoint{}}
|
key := &PublicKey{crypto.ECPoint{}}
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
assert.Nil(t, key.EncodeBinary(buf))
|
assert.Nil(t, key.EncodeBinary(buf))
|
||||||
assert.Equal(t, 1, buf.Len())
|
assert.Equal(t, 1, buf.Len())
|
||||||
|
@ -21,7 +22,7 @@ func TestEncodeDecodeInfinity(t *testing.T) {
|
||||||
|
|
||||||
func TestEncodeDecodePublicKey(t *testing.T) {
|
func TestEncodeDecodePublicKey(t *testing.T) {
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
p := &PublicKey{RandomECPoint()}
|
p := &PublicKey{crypto.RandomECPoint()}
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
assert.Nil(t, p.EncodeBinary(buf))
|
assert.Nil(t, p.EncodeBinary(buf))
|
||||||
|
|
||||||
|
@ -34,8 +35,14 @@ func TestEncodeDecodePublicKey(t *testing.T) {
|
||||||
func TestDecodeFromString(t *testing.T) {
|
func TestDecodeFromString(t *testing.T) {
|
||||||
str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
|
str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
|
||||||
pubKey, err := NewPublicKeyFromString(str)
|
pubKey, err := NewPublicKeyFromString(str)
|
||||||
if err != nil {
|
assert.Nil(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
assert.Equal(t, str, hex.EncodeToString(pubKey.Bytes()))
|
assert.Equal(t, str, hex.EncodeToString(pubKey.Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPubkeyToAddress(t *testing.T) {
|
||||||
|
pubKey, err := NewPublicKeyFromString("031ee4e73a17d8f76dc02532e2620bcb12425b33c0c9f9694cc2caa8226b68cad4")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
actual := pubKey.Address()
|
||||||
|
expected := "AUpGsNCHzSimeMRVPQfhwrVdiUp8Q2N2Qx"
|
||||||
|
assert.Equal(t, expected, actual)
|
||||||
|
}
|
|
@ -1,31 +1,34 @@
|
||||||
package pubkeytesthelper
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/privatekey"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPubKeyVerify(t *testing.T) {
|
func TestPubKeyVerify(t *testing.T) {
|
||||||
actual, err := SignDataWithRandomPrivateKey([]byte("sample"))
|
var data = []byte("sample")
|
||||||
|
hashedData := hash.Sha256(data)
|
||||||
|
|
||||||
if err != nil {
|
privKey, err := NewPrivateKey()
|
||||||
t.Fatal(err)
|
assert.Nil(t, err)
|
||||||
}
|
signedData, err := privKey.Sign(data)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
pubKey, err := privKey.PublicKey()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
result := pubKey.Verify(signedData, hashedData.Bytes())
|
||||||
expected := true
|
expected := true
|
||||||
|
assert.Equal(t, expected, result)
|
||||||
assert.Equal(t, expected, actual)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWrongPubKey(t *testing.T) {
|
func TestWrongPubKey(t *testing.T) {
|
||||||
privKey, _ := privatekey.NewPrivateKey()
|
privKey, _ := NewPrivateKey()
|
||||||
sample := []byte("sample")
|
sample := []byte("sample")
|
||||||
hashedData, _ := hash.Sha256(sample)
|
hashedData := hash.Sha256(sample)
|
||||||
signedData, _ := privKey.Sign(sample)
|
signedData, _ := privKey.Sign(sample)
|
||||||
|
|
||||||
secondPrivKey, _ := privatekey.NewPrivateKey()
|
secondPrivKey, _ := NewPrivateKey()
|
||||||
wrongPubKey, _ := secondPrivKey.PublicKey()
|
wrongPubKey, _ := secondPrivKey.PublicKey()
|
||||||
|
|
||||||
actual := wrongPubKey.Verify(signedData, hashedData.Bytes())
|
actual := wrongPubKey.Verify(signedData, hashedData.Bytes())
|
|
@ -1,4 +1,4 @@
|
||||||
package wallet
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -98,7 +98,7 @@ func (wif WIF) GetVerificationScript() ([]byte, error) {
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
vScript []byte
|
vScript []byte
|
||||||
pubkey *crypto.PublicKey
|
pubkey *PublicKey
|
||||||
)
|
)
|
||||||
pubkey, err := wif.PrivateKey.PublicKey()
|
pubkey, err := wif.PrivateKey.PublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,8 +1,10 @@
|
||||||
package wallet
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wifTestCase struct {
|
type wifTestCase struct {
|
||||||
|
@ -36,29 +38,15 @@ var wifTestCases = []wifTestCase{
|
||||||
func TestWIFEncodeDecode(t *testing.T) {
|
func TestWIFEncodeDecode(t *testing.T) {
|
||||||
for _, testCase := range wifTestCases {
|
for _, testCase := range wifTestCases {
|
||||||
b, err := hex.DecodeString(testCase.privateKey)
|
b, err := hex.DecodeString(testCase.privateKey)
|
||||||
if err != nil {
|
assert.Nil(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
wif, err := WIFEncode(b, testCase.version, testCase.compressed)
|
wif, err := WIFEncode(b, testCase.version, testCase.compressed)
|
||||||
if err != nil {
|
assert.Nil(t, err)
|
||||||
t.Fatal(err)
|
assert.Equal(t, testCase.wif, wif)
|
||||||
}
|
|
||||||
if want, have := testCase.wif, wif; want != have {
|
|
||||||
t.Fatalf("expected %s got %s", want, have)
|
|
||||||
}
|
|
||||||
|
|
||||||
WIF, err := WIFDecode(wif, testCase.version)
|
WIF, err := WIFDecode(wif, testCase.version)
|
||||||
if err != nil {
|
assert.Nil(t, err)
|
||||||
t.Fatal(err)
|
assert.Equal(t, testCase.privateKey, WIF.PrivateKey.String())
|
||||||
}
|
assert.Equal(t, testCase.compressed, WIF.Compressed)
|
||||||
if want, have := testCase.privateKey, WIF.PrivateKey.String(); want != have {
|
assert.Equal(t, testCase.version, WIF.Version)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
37
pkg/internal/keytestcases/testcases.go
Normal file
37
pkg/internal/keytestcases/testcases.go
Normal file
|
@ -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",
|
||||||
|
},
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/wallet"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ type Client struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
version string
|
version string
|
||||||
wifMu *sync.Mutex
|
wifMu *sync.Mutex
|
||||||
wif *wallet.WIF
|
wif *keys.WIF
|
||||||
balancerMu *sync.Mutex
|
balancerMu *sync.Mutex
|
||||||
balancer BalanceGetter
|
balancer BalanceGetter
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ func NewClient(ctx context.Context, endpoint string, opts ClientOptions) (*Clien
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) WIF() wallet.WIF {
|
func (c *Client) WIF() keys.WIF {
|
||||||
c.wifMu.Lock()
|
c.wifMu.Lock()
|
||||||
defer c.wifMu.Unlock()
|
defer c.wifMu.Unlock()
|
||||||
return wallet.WIF{
|
return keys.WIF{
|
||||||
Version: c.wif.Version,
|
Version: c.wif.Version,
|
||||||
Compressed: c.wif.Compressed,
|
Compressed: c.wif.Compressed,
|
||||||
PrivateKey: c.wif.PrivateKey,
|
PrivateKey: c.wif.PrivateKey,
|
||||||
|
@ -109,7 +109,7 @@ func (c *Client) WIF() wallet.WIF {
|
||||||
func (c *Client) SetWIF(wif string) error {
|
func (c *Client) SetWIF(wif string) error {
|
||||||
c.wifMu.Lock()
|
c.wifMu.Lock()
|
||||||
defer c.wifMu.Unlock()
|
defer c.wifMu.Unlock()
|
||||||
decodedWif, err := wallet.WIFDecode(wif, 0x00)
|
decodedWif, err := keys.WIFDecode(wif, 0x00)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed to decode WIF; failed to add WIF to client ")
|
return errors.Wrap(err, "Failed to decode WIF; failed to add WIF to client ")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"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/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/wallet"
|
|
||||||
errs "github.com/pkg/errors"
|
errs "github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ func CreateRawContractTransaction(params ContractTxParams) (*transaction.Transac
|
||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetInvocationScript(tx *transaction.Transaction, wif wallet.WIF) ([]byte, error) {
|
func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, error) {
|
||||||
const (
|
const (
|
||||||
pushbytes64 = 0x40
|
pushbytes64 = 0x40
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/wallet"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -19,7 +19,7 @@ type (
|
||||||
assetId util.Uint256
|
assetId util.Uint256
|
||||||
address string
|
address string
|
||||||
value util.Fixed8
|
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,
|
// since there are many ways to provide unspents,
|
||||||
// transaction composer stays agnostic to that how
|
// transaction composer stays agnostic to that how
|
||||||
// unspents was got;
|
// unspents was got;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"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"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ type AccountState struct {
|
||||||
Version uint8 `json:"version"`
|
Version uint8 `json:"version"`
|
||||||
ScriptHash util.Uint160 `json:"script_hash"`
|
ScriptHash util.Uint160 `json:"script_hash"`
|
||||||
IsFrozen bool `json:"frozen"`
|
IsFrozen bool `json:"frozen"`
|
||||||
Votes []*crypto.PublicKey `json:"votes"`
|
Votes []*keys.PublicKey `json:"votes"`
|
||||||
Balances []Balance `json:"balances"`
|
Balances []Balance `json:"balances"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateMultiSigRedeemScript will create a script runnable by the 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 {
|
if m <= 1 {
|
||||||
return nil, fmt.Errorf("param m cannot be smaller or equal to 1 got %d", m)
|
return nil, fmt.Errorf("param m cannot be smaller or equal to 1 got %d", m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,18 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"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/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm"
|
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateMultiSigRedeemScript(t *testing.T) {
|
func TestCreateMultiSigRedeemScript(t *testing.T) {
|
||||||
val1, _ := crypto.NewPublicKeyFromString("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c")
|
val1, _ := keys.NewPublicKeyFromString("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c")
|
||||||
val2, _ := crypto.NewPublicKeyFromString("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093")
|
val2, _ := keys.NewPublicKeyFromString("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093")
|
||||||
val3, _ := crypto.NewPublicKeyFromString("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a")
|
val3, _ := keys.NewPublicKeyFromString("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a")
|
||||||
|
|
||||||
validators := []*crypto.PublicKey{val1, val2, val3}
|
validators := []*keys.PublicKey{val1, val2, val3}
|
||||||
|
|
||||||
out, err := CreateMultiSigRedeemScript(3, validators)
|
out, err := CreateMultiSigRedeemScript(3, validators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package wallet
|
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
|
// Account represents a NEO account. It holds the private and public key
|
||||||
// along with some metadata.
|
// along with some metadata.
|
||||||
type Account struct {
|
type Account struct {
|
||||||
// NEO private key.
|
// NEO private key.
|
||||||
privateKey *PrivateKey
|
privateKey *keys.PrivateKey
|
||||||
|
|
||||||
// NEO public key.
|
// NEO public key.
|
||||||
publicKey []byte
|
publicKey []byte
|
||||||
|
@ -50,7 +53,7 @@ type Contract struct {
|
||||||
|
|
||||||
// NewAccount creates a new Account with a random generated PrivateKey.
|
// NewAccount creates a new Account with a random generated PrivateKey.
|
||||||
func NewAccount() (*Account, error) {
|
func NewAccount() (*Account, error) {
|
||||||
priv, err := NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -60,7 +63,7 @@ func NewAccount() (*Account, error) {
|
||||||
// DecryptAccount decrypt the encryptedWIF with the given passphrase and
|
// DecryptAccount decrypt the encryptedWIF with the given passphrase and
|
||||||
// return the decrypted Account.
|
// return the decrypted Account.
|
||||||
func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) {
|
func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) {
|
||||||
wif, err := NEP2Decrypt(encryptedWIF, passphrase)
|
wif, err := keys.NEP2Decrypt(encryptedWIF, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -70,7 +73,7 @@ func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) {
|
||||||
// Encrypt encrypts the wallet's PrivateKey with the given passphrase
|
// Encrypt encrypts the wallet's PrivateKey with the given passphrase
|
||||||
// under the NEP-2 standard.
|
// under the NEP-2 standard.
|
||||||
func (a *Account) Encrypt(passphrase string) error {
|
func (a *Account) Encrypt(passphrase string) error {
|
||||||
wif, err := NEP2Encrypt(a.privateKey, passphrase)
|
wif, err := keys.NEP2Encrypt(a.privateKey, passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -80,7 +83,7 @@ func (a *Account) Encrypt(passphrase string) error {
|
||||||
|
|
||||||
// NewAccountFromWIF creates a new Account from the given WIF.
|
// NewAccountFromWIF creates a new Account from the given WIF.
|
||||||
func NewAccountFromWIF(wif string) (*Account, error) {
|
func NewAccountFromWIF(wif string) (*Account, error) {
|
||||||
privKey, err := NewPrivateKeyFromWIF(wif)
|
privKey, err := keys.NewPrivateKeyFromWIF(wif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -88,7 +91,7 @@ func NewAccountFromWIF(wif string) (*Account, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newAccountFromPrivateKey created a wallet from the given PrivateKey.
|
// 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()
|
pubKey, err := p.PublicKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -3,11 +3,13 @@ package wallet
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/internal/keytestcases"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewAccount(t *testing.T) {
|
func TestNewAccount(t *testing.T) {
|
||||||
for _, testCase := range testKeyCases {
|
for _, testCase := range keytestcases.Arr {
|
||||||
acc, err := NewAccountFromWIF(testCase.wif)
|
acc, err := NewAccountFromWIF(testCase.Wif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -16,8 +18,8 @@ func TestNewAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptAccount(t *testing.T) {
|
func TestDecryptAccount(t *testing.T) {
|
||||||
for _, testCase := range testKeyCases {
|
for _, testCase := range keytestcases.Arr {
|
||||||
acc, err := DecryptAccount(testCase.encryptedWif, testCase.passphrase)
|
acc, err := DecryptAccount(testCase.EncryptedWif, testCase.Passphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -26,8 +28,8 @@ func TestDecryptAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewFromWif(t *testing.T) {
|
func TestNewFromWif(t *testing.T) {
|
||||||
for _, testCase := range testKeyCases {
|
for _, testCase := range keytestcases.Arr {
|
||||||
acc, err := NewAccountFromWIF(testCase.wif)
|
acc, err := NewAccountFromWIF(testCase.Wif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -35,17 +37,17 @@ func TestNewFromWif(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareFields(t *testing.T, tk testKey, acc *Account) {
|
func compareFields(t *testing.T, tk keytestcases.Ktype, acc *Account) {
|
||||||
if want, have := tk.address, acc.Address; want != have {
|
if want, have := tk.Address, acc.Address; want != have {
|
||||||
t.Fatalf("expected %s got %s", 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)
|
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)
|
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)
|
t.Fatalf("expected %s got %s", want, have)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package wallet
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNEP2Encrypt(t *testing.T) {
|
|
||||||
for _, testCase := range testKeyCases {
|
|
||||||
|
|
||||||
privKey, err := NewPrivateKeyFromHex(testCase.privateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
encryptedWif, err := NEP2Encrypt(privKey, testCase.passphrase)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
privKeyString, err := NEP2Decrypt(testCase.encryptedWif, testCase.passphrase)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
privKey, err := NewPrivateKeyFromWIF(privKeyString)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if want, have := testCase.privateKey, privKey.String(); 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -20,7 +22,7 @@ type Wallet struct {
|
||||||
// in the wallet.
|
// in the wallet.
|
||||||
Accounts []*Account `json:"accounts"`
|
Accounts []*Account `json:"accounts"`
|
||||||
|
|
||||||
Scrypt scryptParams `json:"scrypt"`
|
Scrypt keys.ScryptParams `json:"scrypt"`
|
||||||
|
|
||||||
// Extra metadata can be used for storing arbitrary data.
|
// Extra metadata can be used for storing arbitrary data.
|
||||||
// This field can be empty.
|
// This field can be empty.
|
||||||
|
@ -66,7 +68,7 @@ func newWallet(rw io.ReadWriter) *Wallet {
|
||||||
return &Wallet{
|
return &Wallet{
|
||||||
Version: walletVersion,
|
Version: walletVersion,
|
||||||
Accounts: []*Account{},
|
Accounts: []*Account{},
|
||||||
Scrypt: newScryptParams(),
|
Scrypt: keys.NEP2ScryptParams(),
|
||||||
rw: rw,
|
rw: rw,
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue