128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
package address
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"errors"
|
|
"filippo.io/edwards25519"
|
|
"git.gammaspectra.live/P2Pool/moneroutil"
|
|
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
|
|
"golang.org/x/crypto/sha3"
|
|
)
|
|
|
|
type Address struct {
|
|
Network uint8
|
|
SpendPub edwards25519.Point
|
|
ViewPub edwards25519.Point
|
|
Checksum []byte
|
|
}
|
|
|
|
var scalar8, _ = edwards25519.NewScalar().SetCanonicalBytes([]byte{8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
|
|
|
func FromBase58(address string) *Address {
|
|
raw := moneroutil.DecodeMoneroBase58(address)
|
|
|
|
if len(raw) != 69 {
|
|
return nil
|
|
}
|
|
checksum := moneroutil.GetChecksum(raw[:65])
|
|
if bytes.Compare(checksum[:], raw[65:]) != 0 {
|
|
return nil
|
|
}
|
|
a := &Address{
|
|
Network: raw[0],
|
|
Checksum: checksum[:],
|
|
}
|
|
|
|
if _, err := a.SpendPub.SetBytes(raw[1:33]); err != nil {
|
|
return nil
|
|
}
|
|
if _, err := a.ViewPub.SetBytes(raw[33:65]); err != nil {
|
|
return nil
|
|
}
|
|
|
|
return a
|
|
}
|
|
|
|
func FromRawAddress(network uint8, spend, view types.Hash) *Address {
|
|
nice := make([]byte, 69)
|
|
nice[0] = network
|
|
copy(nice[1:], spend[:])
|
|
copy(nice[33:], view[:])
|
|
|
|
checksum := moneroutil.GetChecksum(nice[:65])
|
|
a := &Address{
|
|
Network: nice[0],
|
|
Checksum: checksum[:],
|
|
}
|
|
|
|
if _, err := a.SpendPub.SetBytes(nice[1:33]); err != nil {
|
|
return nil
|
|
}
|
|
if _, err := a.ViewPub.SetBytes(nice[33:65]); err != nil {
|
|
return nil
|
|
}
|
|
|
|
return a
|
|
}
|
|
|
|
func (a *Address) ToBase58() string {
|
|
return moneroutil.EncodeMoneroBase58([]byte{a.Network}, a.SpendPub.Bytes(), a.ViewPub.Bytes(), a.Checksum[:])
|
|
}
|
|
|
|
func (a *Address) GetDerivationForPrivateKey(privateKey *edwards25519.Scalar) *edwards25519.Point {
|
|
point := (&edwards25519.Point{}).ScalarMult(privateKey, &a.ViewPub)
|
|
return (&edwards25519.Point{}).ScalarMult(scalar8, point)
|
|
}
|
|
|
|
func GetDerivationSharedDataForOutputIndex(derivation *edwards25519.Point, outputIndex uint64) *edwards25519.Scalar {
|
|
varIntBuf := make([]byte, binary.MaxVarintLen64)
|
|
data := append(derivation.Bytes(), varIntBuf[:binary.PutUvarint(varIntBuf, outputIndex)]...)
|
|
hasher := sha3.NewLegacyKeccak256()
|
|
if _, err := hasher.Write(data); err != nil {
|
|
return nil
|
|
}
|
|
|
|
var wideBytes [64]byte
|
|
copy(wideBytes[:], hasher.Sum([]byte{}))
|
|
scalar, _ := edwards25519.NewScalar().SetUniformBytes(wideBytes[:])
|
|
|
|
return scalar
|
|
}
|
|
|
|
func (a *Address) GetPublicKeyForSharedData(sharedData *edwards25519.Scalar) *edwards25519.Point {
|
|
sG := (&edwards25519.Point{}).ScalarBaseMult(sharedData)
|
|
|
|
return (&edwards25519.Point{}).Add(sG, &a.SpendPub)
|
|
|
|
}
|
|
|
|
func (a *Address) GetEphemeralPublicKey(privateKey types.Hash, outputIndex uint64) (result types.Hash) {
|
|
pK, _ := edwards25519.NewScalar().SetCanonicalBytes(privateKey[:])
|
|
copy(result[:], a.GetPublicKeyForSharedData(GetDerivationSharedDataForOutputIndex(a.GetDerivationForPrivateKey(pK), outputIndex)).Bytes())
|
|
|
|
return
|
|
}
|
|
|
|
func (a *Address) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(a.ToBase58())
|
|
}
|
|
|
|
func (a *Address) UnmarshalJSON(b []byte) error {
|
|
var s string
|
|
if err := json.Unmarshal(b, &s); err != nil {
|
|
return err
|
|
}
|
|
|
|
if addr := FromBase58(s); addr != nil {
|
|
a.Network = addr.Network
|
|
a.SpendPub = addr.SpendPub
|
|
a.ViewPub = addr.ViewPub
|
|
a.Checksum = addr.Checksum
|
|
return nil
|
|
} else {
|
|
return errors.New("invalid address")
|
|
}
|
|
}
|