refactor and use interfaces!
This commit is contained in:
parent
025ef20056
commit
bd6487d1f6
70
key.go
Normal file
70
key.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package moneroutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PointLength = 32
|
||||||
|
ScalarLength = 32
|
||||||
|
)
|
||||||
|
|
||||||
|
type PubKey [PointLength]byte
|
||||||
|
type PrivKey [ScalarLength]byte
|
||||||
|
|
||||||
|
func (p *PrivKey) FromBytes(b [ScalarLength]byte) {
|
||||||
|
*p = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivKey) ToBytes() (result [ScalarLength]byte) {
|
||||||
|
result = [32]byte(*p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrivKey) PubKey() (pubKey *PubKey) {
|
||||||
|
secret := p.ToBytes()
|
||||||
|
point := new(ExtendedGroupElement)
|
||||||
|
GeScalarMultBase(point, &secret)
|
||||||
|
pubKeyBytes := new([PointLength]byte)
|
||||||
|
point.ToBytes(pubKeyBytes)
|
||||||
|
pubKey = (*PubKey)(pubKeyBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PubKey) FromBytes(b [PointLength]byte) {
|
||||||
|
*p = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PubKey) ToBytes() (result [PointLength]byte) {
|
||||||
|
result = [PointLength]byte(*p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a point on the Edwards Curve by hashing the key
|
||||||
|
func (p *PubKey) HashToEC() (result *ExtendedGroupElement) {
|
||||||
|
result = new(ExtendedGroupElement)
|
||||||
|
var p1 ProjectiveGroupElement
|
||||||
|
var p2 CompletedGroupElement
|
||||||
|
h := [PointLength]byte(Keccak256(p[:]))
|
||||||
|
p1.FromBytes(&h)
|
||||||
|
GeMul8(&p2, &p1)
|
||||||
|
p2.ToExtended(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandomScalar() (result [ScalarLength]byte) {
|
||||||
|
var reduceFrom [ScalarLength * 2]byte
|
||||||
|
tmp := make([]byte, ScalarLength*2)
|
||||||
|
rand.Read(tmp)
|
||||||
|
copy(reduceFrom[:], tmp)
|
||||||
|
ScReduce(&result, &reduceFrom)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKeyPair() (privKey *PrivKey, pubKey *PubKey) {
|
||||||
|
privKey = new(PrivKey)
|
||||||
|
pubKey = new(PubKey)
|
||||||
|
privKey.FromBytes(RandomScalar())
|
||||||
|
pubKey = privKey.PubKey()
|
||||||
|
return
|
||||||
|
}
|
112
ringsignature.go
112
ringsignature.go
|
@ -1,20 +1,11 @@
|
||||||
package moneroutil
|
package moneroutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
mathrand "math/rand"
|
"io"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
PointLength = 32
|
|
||||||
ScalarLength = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
type PubKey [PointLength]byte
|
|
||||||
type PrivKey [ScalarLength]byte
|
|
||||||
|
|
||||||
type RingSignatureElement struct {
|
type RingSignatureElement struct {
|
||||||
c [ScalarLength]byte
|
c [ScalarLength]byte
|
||||||
r [ScalarLength]byte
|
r [ScalarLength]byte
|
||||||
|
@ -22,80 +13,48 @@ type RingSignatureElement struct {
|
||||||
|
|
||||||
type RingSignature []*RingSignatureElement
|
type RingSignature []*RingSignatureElement
|
||||||
|
|
||||||
func RandomScalar() (result [ScalarLength]byte) {
|
func (r *RingSignatureElement) Serialize() (result []byte) {
|
||||||
var reduceFrom [ScalarLength * 2]byte
|
|
||||||
tmp := make([]byte, ScalarLength*2)
|
|
||||||
rand.Read(tmp)
|
|
||||||
copy(reduceFrom[:], tmp)
|
|
||||||
ScReduce(&result, &reduceFrom)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PrivKey) FromBytes(b [ScalarLength]byte) {
|
|
||||||
*p = b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PrivKey) ToBytes() (result [ScalarLength]byte) {
|
|
||||||
result = [32]byte(*p)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PrivKey) PubKey() (pubKey *PubKey) {
|
|
||||||
secret := p.ToBytes()
|
|
||||||
point := new(ExtendedGroupElement)
|
|
||||||
GeScalarMultBase(point, &secret)
|
|
||||||
pubKeyBytes := new([PointLength]byte)
|
|
||||||
point.ToBytes(pubKeyBytes)
|
|
||||||
pubKey = (*PubKey)(pubKeyBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PubKey) ToBytes() (result [PointLength]byte) {
|
|
||||||
result = [PointLength]byte(*p)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyPair() (privKey *PrivKey, pubKey *PubKey) {
|
|
||||||
privKey = new(PrivKey)
|
|
||||||
pubKey = new(PubKey)
|
|
||||||
privKey.FromBytes(RandomScalar())
|
|
||||||
pubKey = privKey.PubKey()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RingSignatureElement) Serialize() (result []byte) {
|
|
||||||
result = make([]byte, 2*ScalarLength)
|
result = make([]byte, 2*ScalarLength)
|
||||||
copy(result, s.c[:])
|
copy(result[:ScalarLength], r.c[:])
|
||||||
copy(result[ScalarLength:2*ScalarLength], s.r[:])
|
copy(result[ScalarLength:2*ScalarLength], r.r[:])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RingSignature) Serialize() (result []byte) {
|
func (r *RingSignature) Serialize() (result []byte) {
|
||||||
|
result = make([]byte, len(*r)*ScalarLength*2)
|
||||||
for i := 0; i < len(*r); i++ {
|
for i := 0; i < len(*r); i++ {
|
||||||
result = append(result, (*r)[i].Serialize()...)
|
copy(result[i*ScalarLength*2:(i+1)*ScalarLength*2], (*r)[i].Serialize())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseSignature(buf *bytes.Buffer) (result *RingSignatureElement, err error) {
|
func ParseSignature(buf io.Reader) (result *RingSignatureElement, err error) {
|
||||||
s := new(RingSignatureElement)
|
rse := new(RingSignatureElement)
|
||||||
c := buf.Next(ScalarLength)
|
c := make([]byte, ScalarLength)
|
||||||
if len(c) != ScalarLength {
|
n, err := buf.Read(c)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != ScalarLength {
|
||||||
err = fmt.Errorf("Not enough bytes for signature c")
|
err = fmt.Errorf("Not enough bytes for signature c")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(s.c[:], c)
|
copy(rse.c[:], c)
|
||||||
r := buf.Next(ScalarLength)
|
r := make([]byte, ScalarLength)
|
||||||
if len(r) != ScalarLength {
|
n, err = buf.Read(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != ScalarLength {
|
||||||
err = fmt.Errorf("Not enough bytes for signature r")
|
err = fmt.Errorf("Not enough bytes for signature r")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(s.r[:], r)
|
copy(rse.r[:], r)
|
||||||
result = s
|
result = rse
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseSignatures(mixinLengths []int, buf *bytes.Buffer) (signatures []RingSignature, err error) {
|
func ParseSignatures(mixinLengths []int, buf io.Reader) (signatures []RingSignature, err error) {
|
||||||
// mixinLengths is the number of mixins at each input position
|
// mixinLengths is the number of mixins at each input position
|
||||||
sigs := make([]RingSignature, len(mixinLengths), len(mixinLengths))
|
sigs := make([]RingSignature, len(mixinLengths), len(mixinLengths))
|
||||||
for i, nMixin := range mixinLengths {
|
for i, nMixin := range mixinLengths {
|
||||||
|
@ -111,16 +70,6 @@ func ParseSignatures(mixinLengths []int, buf *bytes.Buffer) (signatures []RingSi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashes a pubkey into an Edwards Curve element
|
|
||||||
func HashToEC(pk *PubKey, r *ExtendedGroupElement) {
|
|
||||||
var p1 ProjectiveGroupElement
|
|
||||||
var p2 CompletedGroupElement
|
|
||||||
h := [PointLength]byte(Keccak256(pk[:]))
|
|
||||||
p1.FromBytes(&h)
|
|
||||||
GeMul8(&p2, &p1)
|
|
||||||
p2.ToExtended(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func HashToScalar(data ...[]byte) (result [ScalarLength]byte) {
|
func HashToScalar(data ...[]byte) (result [ScalarLength]byte) {
|
||||||
result = Keccak256(data...)
|
result = Keccak256(data...)
|
||||||
ScReduce32(&result)
|
ScReduce32(&result)
|
||||||
|
@ -128,8 +77,7 @@ func HashToScalar(data ...[]byte) (result [ScalarLength]byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyImage PubKey, pubKeys []PubKey, sig RingSignature) {
|
func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyImage PubKey, pubKeys []PubKey, sig RingSignature) {
|
||||||
point := new(ExtendedGroupElement)
|
point := privKey.PubKey().HashToEC()
|
||||||
HashToEC(privKey.PubKey(), point)
|
|
||||||
privKeyBytes := privKey.ToBytes()
|
privKeyBytes := privKey.ToBytes()
|
||||||
keyImagePoint := new(ProjectiveGroupElement)
|
keyImagePoint := new(ProjectiveGroupElement)
|
||||||
GeScalarMult(keyImagePoint, &privKeyBytes, point)
|
GeScalarMult(keyImagePoint, &privKeyBytes, point)
|
||||||
|
@ -144,7 +92,7 @@ func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyIm
|
||||||
GePrecompute(&keyImagePre, keyImageGe)
|
GePrecompute(&keyImagePre, keyImageGe)
|
||||||
k := RandomScalar()
|
k := RandomScalar()
|
||||||
pubKeys = make([]PubKey, len(mixins)+1)
|
pubKeys = make([]PubKey, len(mixins)+1)
|
||||||
privIndex := mathrand.Intn(len(pubKeys))
|
privIndex := rand.Intn(len(pubKeys))
|
||||||
pubKeys[privIndex] = *privKey.PubKey()
|
pubKeys[privIndex] = *privKey.PubKey()
|
||||||
r := make([]*RingSignatureElement, len(pubKeys))
|
r := make([]*RingSignatureElement, len(pubKeys))
|
||||||
var sum [ScalarLength]byte
|
var sum [ScalarLength]byte
|
||||||
|
@ -157,7 +105,7 @@ func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyIm
|
||||||
GeScalarMultBase(tmpE, &k)
|
GeScalarMultBase(tmpE, &k)
|
||||||
tmpE.ToBytes(&tmpEBytes)
|
tmpE.ToBytes(&tmpEBytes)
|
||||||
toHash = append(toHash, tmpEBytes[:]...)
|
toHash = append(toHash, tmpEBytes[:]...)
|
||||||
HashToEC(privKey.PubKey(), tmpE)
|
tmpE = privKey.PubKey().HashToEC()
|
||||||
GeScalarMult(tmpP, &k, tmpE)
|
GeScalarMult(tmpP, &k, tmpE)
|
||||||
tmpP.ToBytes(&tmpPBytes)
|
tmpP.ToBytes(&tmpPBytes)
|
||||||
toHash = append(toHash, tmpPBytes[:]...)
|
toHash = append(toHash, tmpPBytes[:]...)
|
||||||
|
@ -176,7 +124,7 @@ func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyIm
|
||||||
GeDoubleScalarMultVartime(tmpP, &r[i].c, tmpE, &r[i].r)
|
GeDoubleScalarMultVartime(tmpP, &r[i].c, tmpE, &r[i].r)
|
||||||
tmpP.ToBytes(&tmpPBytes)
|
tmpP.ToBytes(&tmpPBytes)
|
||||||
toHash = append(toHash, tmpPBytes[:]...)
|
toHash = append(toHash, tmpPBytes[:]...)
|
||||||
HashToEC(&pubKeys[i], tmpE)
|
tmpE = pubKeys[i].HashToEC()
|
||||||
GeDoubleScalarMultPrecompVartime(tmpP, &r[i].r, tmpE, &r[i].c, &keyImagePre)
|
GeDoubleScalarMultPrecompVartime(tmpP, &r[i].r, tmpE, &r[i].c, &keyImagePre)
|
||||||
tmpP.ToBytes(&tmpPBytes)
|
tmpP.ToBytes(&tmpPBytes)
|
||||||
toHash = append(toHash, tmpPBytes[:]...)
|
toHash = append(toHash, tmpPBytes[:]...)
|
||||||
|
@ -220,7 +168,7 @@ func VerifySignature(prefixHash *Hash, keyImage *PubKey, pubKeys []PubKey, ringS
|
||||||
GeDoubleScalarMultVartime(tmpP, &rse.c, tmpE, &rse.r)
|
GeDoubleScalarMultVartime(tmpP, &rse.c, tmpE, &rse.r)
|
||||||
tmpP.ToBytes(&tmpPBytes)
|
tmpP.ToBytes(&tmpPBytes)
|
||||||
toHash = append(toHash, tmpPBytes[:]...)
|
toHash = append(toHash, tmpPBytes[:]...)
|
||||||
HashToEC(&pubKey, tmpE)
|
tmpE = pubKey.HashToEC()
|
||||||
tmpE.ToBytes(&tmpEBytes)
|
tmpE.ToBytes(&tmpEBytes)
|
||||||
GeDoubleScalarMultPrecompVartime(tmpP, &rse.r, tmpE, &rse.c, &keyImagePre)
|
GeDoubleScalarMultPrecompVartime(tmpP, &rse.r, tmpE, &rse.c, &keyImagePre)
|
||||||
tmpP.ToBytes(&tmpPBytes)
|
tmpP.ToBytes(&tmpPBytes)
|
||||||
|
|
|
@ -1799,10 +1799,10 @@ func TestHashToEC(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
pubkeyBytes := HexToBytes(test.pubkeyHex)
|
pubkeyBytes := HexToBytes(test.pubkeyHex)
|
||||||
pubKey := PubKey(pubkeyBytes)
|
pubKey := new(PubKey)
|
||||||
|
pubKey.FromBytes(pubkeyBytes)
|
||||||
want := HexToBytes(test.extendedHex)
|
want := HexToBytes(test.extendedHex)
|
||||||
ecPoint := new(ExtendedGroupElement)
|
ecPoint := pubKey.HashToEC()
|
||||||
HashToEC(&pubKey, ecPoint)
|
|
||||||
var got [32]byte
|
var got [32]byte
|
||||||
ecPoint.ToBytes(&got)
|
ecPoint.ToBytes(&got)
|
||||||
if want != got {
|
if want != got {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package moneroutil
|
package moneroutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -213,7 +212,7 @@ func (t *Transaction) Serialize() (result []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxInGen(buf *bytes.Buffer) (txIn *txInGen, err error) {
|
func ParseTxInGen(buf io.Reader) (txIn *txInGen, err error) {
|
||||||
t := new(txInGen)
|
t := new(txInGen)
|
||||||
t.height, err = ReadVarInt(buf)
|
t.height, err = ReadVarInt(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -223,17 +222,17 @@ func ParseTxInGen(buf *bytes.Buffer) (txIn *txInGen, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxInToScript(buf *bytes.Buffer) (txIn *txInToScript, err error) {
|
func ParseTxInToScript(buf io.Reader) (txIn *txInToScript, err error) {
|
||||||
err = errors.New("Unimplemented")
|
err = fmt.Errorf("Unimplemented")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxInToScriptHash(buf *bytes.Buffer) (txIn *txInToScriptHash, err error) {
|
func ParseTxInToScriptHash(buf io.Reader) (txIn *txInToScriptHash, err error) {
|
||||||
err = errors.New("Unimplemented")
|
err = fmt.Errorf("Unimplemented")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxInToKey(buf *bytes.Buffer) (txIn *txInToKey, err error) {
|
func ParseTxInToKey(buf io.Reader) (txIn *txInToKey, err error) {
|
||||||
t := new(txInToKey)
|
t := new(txInToKey)
|
||||||
t.amount, err = ReadVarInt(buf)
|
t.amount, err = ReadVarInt(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -250,9 +249,13 @@ func ParseTxInToKey(buf *bytes.Buffer) (txIn *txInToKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pubKey := buf.Next(PointLength)
|
pubKey := make([]byte, PointLength)
|
||||||
if len(pubKey) != PointLength {
|
n, err := buf.Read(pubKey)
|
||||||
err = errors.New("Buffer not long enough for public key")
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != PointLength {
|
||||||
|
err = fmt.Errorf("Buffer not long enough for public key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(t.keyImage[:], pubKey)
|
copy(t.keyImage[:], pubKey)
|
||||||
|
@ -260,39 +263,48 @@ func ParseTxInToKey(buf *bytes.Buffer) (txIn *txInToKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxIn(buf *bytes.Buffer) (txIn TxInSerializer, err error) {
|
func ParseTxIn(buf io.Reader) (txIn TxInSerializer, err error) {
|
||||||
marker, err := buf.ReadByte()
|
marker := make([]byte, 1)
|
||||||
|
n, err := buf.Read(marker)
|
||||||
|
if n != 1 {
|
||||||
|
err = fmt.Errorf("Buffer not enough for TxIn")
|
||||||
|
return
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case marker == txInGenMarker:
|
case marker[0] == txInGenMarker:
|
||||||
txIn, err = ParseTxInGen(buf)
|
txIn, err = ParseTxInGen(buf)
|
||||||
case marker == txInToScriptMarker:
|
case marker[0] == txInToScriptMarker:
|
||||||
txIn, err = ParseTxInToScript(buf)
|
txIn, err = ParseTxInToScript(buf)
|
||||||
case marker == txInToScriptHashMarker:
|
case marker[0] == txInToScriptHashMarker:
|
||||||
txIn, err = ParseTxInToScriptHash(buf)
|
txIn, err = ParseTxInToScriptHash(buf)
|
||||||
case marker == txInToKeyMarker:
|
case marker[0] == txInToKeyMarker:
|
||||||
txIn, err = ParseTxInToKey(buf)
|
txIn, err = ParseTxInToKey(buf)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxOutToScript(buf *bytes.Buffer) (txOutTarget *txOutToScript, err error) {
|
func ParseTxOutToScript(buf io.Reader) (txOutTarget *txOutToScript, err error) {
|
||||||
err = errors.New("Unimplemented")
|
err = fmt.Errorf("Unimplemented")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxOutToScriptHash(buf *bytes.Buffer) (txOutTarget *txOutToScriptHash, err error) {
|
func ParseTxOutToScriptHash(buf io.Reader) (txOutTarget *txOutToScriptHash, err error) {
|
||||||
err = errors.New("Unimplemented")
|
err = fmt.Errorf("Unimplemented")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxOutToKey(buf *bytes.Buffer) (txOutTarget *txOutToKey, err error) {
|
func ParseTxOutToKey(buf io.Reader) (txOutTarget *txOutToKey, err error) {
|
||||||
t := new(txOutToKey)
|
t := new(txOutToKey)
|
||||||
pubKey := buf.Next(PointLength)
|
pubKey := make([]byte, PointLength)
|
||||||
if len(pubKey) != PointLength {
|
n, err := buf.Read(pubKey)
|
||||||
err = errors.New("Buffer not long enough for public key")
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != PointLength {
|
||||||
|
err = fmt.Errorf("Buffer not long enough for public key")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
copy(t.key[:], pubKey)
|
copy(t.key[:], pubKey)
|
||||||
|
@ -300,25 +312,30 @@ func ParseTxOutToKey(buf *bytes.Buffer) (txOutTarget *txOutToKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTxOut(buf *bytes.Buffer) (txOut *TxOut, err error) {
|
func ParseTxOut(buf io.Reader) (txOut *TxOut, err error) {
|
||||||
t := new(TxOut)
|
t := new(TxOut)
|
||||||
t.amount, err = ReadVarInt(buf)
|
t.amount, err = ReadVarInt(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
marker, err := buf.ReadByte()
|
marker := make([]byte, 1)
|
||||||
|
n, err := buf.Read(marker)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if n != 1 {
|
||||||
|
err = fmt.Errorf("Buffer not long enough for TxOut")
|
||||||
|
return
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case marker == txOutToScriptMarker:
|
case marker[0] == txOutToScriptMarker:
|
||||||
t.target, err = ParseTxOutToScript(buf)
|
t.target, err = ParseTxOutToScript(buf)
|
||||||
case marker == txOutToScriptHashMarker:
|
case marker[0] == txOutToScriptHashMarker:
|
||||||
t.target, err = ParseTxOutToScriptHash(buf)
|
t.target, err = ParseTxOutToScriptHash(buf)
|
||||||
case marker == txOutToKeyMarker:
|
case marker[0] == txOutToKeyMarker:
|
||||||
t.target, err = ParseTxOutToKey(buf)
|
t.target, err = ParseTxOutToKey(buf)
|
||||||
default:
|
default:
|
||||||
err = errors.New("Bad Marker")
|
err = fmt.Errorf("Bad Marker")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -328,21 +345,25 @@ func ParseTxOut(buf *bytes.Buffer) (txOut *TxOut, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseExtra(buf *bytes.Buffer) (extra []byte, err error) {
|
func ParseExtra(buf io.Reader) (extra []byte, err error) {
|
||||||
length, err := ReadVarInt(buf)
|
length, err := ReadVarInt(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e := buf.Next(int(length))
|
e := make([]byte, int(length))
|
||||||
if len(e) != int(length) {
|
n, err := buf.Read(e)
|
||||||
err = errors.New("Not enough bytes for extra")
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != int(length) {
|
||||||
|
err = fmt.Errorf("Not enough bytes for extra")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
extra = e
|
extra = e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseTransaction(buf *bytes.Buffer) (transaction *Transaction, err error) {
|
func ParseTransaction(buf io.Reader) (transaction *Transaction, err error) {
|
||||||
t := new(Transaction)
|
t := new(Transaction)
|
||||||
version, err := ReadVarInt(buf)
|
version, err := ReadVarInt(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -388,10 +409,6 @@ func ParseTransaction(buf *bytes.Buffer) (transaction *Transaction, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if buf.Len() != 0 {
|
|
||||||
err = errors.New("Buffer has extra data")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
transaction = t
|
transaction = t
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
20
varint.go
20
varint.go
|
@ -1,21 +1,29 @@
|
||||||
package moneroutil
|
package moneroutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"fmt"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadVarInt(buf *bytes.Buffer) (result uint64, err error) {
|
func ReadVarInt(buf io.Reader) (result uint64, err error) {
|
||||||
var b byte
|
b := make([]byte, 1)
|
||||||
|
var r uint64
|
||||||
|
var n int
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
b, err = buf.ReadByte()
|
n, err = buf.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result += (uint64(b) & 0x7f) << uint(i*7)
|
if n != 1 {
|
||||||
if uint64(b)&0x80 == 0 {
|
err = fmt.Errorf("Buffer ended prematurely for varint")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r += (uint64(b[0]) & 0x7f) << uint(i*7)
|
||||||
|
if uint64(b[0])&0x80 == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result = r
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue