mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
implement the api for generateOneTimeAddress
This commit is contained in:
parent
523292bb53
commit
f2f4fec6ea
4 changed files with 201 additions and 0 deletions
|
|
@ -21,6 +21,7 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -29,6 +30,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
|
|
@ -272,6 +274,66 @@ func keyFileName(keyAddr common.Address) string {
|
|||
return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
|
||||
}
|
||||
|
||||
// GeneratePKPairFromUAddress represents the keystore to retrieve public key-pair from given UAddress
|
||||
func GeneratePKPairFromUAddress(w []byte) (*ecdsa.PublicKey, *ecdsa.PublicKey, error) {
|
||||
if len(w) != common.UAddressLength {
|
||||
return nil, nil, ErrUAddressInvalid
|
||||
}
|
||||
|
||||
tmp := make([]byte, 33)
|
||||
copy(tmp[:], w[:33])
|
||||
curve := btcec.S256()
|
||||
PK1, err := btcec.ParsePubKey(tmp, curve)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
copy(tmp[:], w[33:])
|
||||
PK2, err := btcec.ParsePubKey(tmp, curve)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return (*ecdsa.PublicKey)(PK1), (*ecdsa.PublicKey)(PK2), nil
|
||||
}
|
||||
|
||||
func UaddrFromUncompressedRawBytes(raw []byte) (*common.UAddress, error) {
|
||||
if len(raw) != 32*2*2 {
|
||||
return nil, errors.New("invalid uncompressed use address len")
|
||||
}
|
||||
|
||||
pub := make([]byte, 65)
|
||||
pub[0] = 0x004
|
||||
copy(pub[1:], raw[:64])
|
||||
A := crypto.ToECDSAPub(pub)
|
||||
copy(pub[1:], raw[64:])
|
||||
B := crypto.ToECDSAPub(pub)
|
||||
return GenerateUaddressFromPK(A, B), nil
|
||||
}
|
||||
|
||||
func UaddrToUncompressedRawBytes(waddr []byte) ([]byte, error) {
|
||||
if len(waddr) != common.UAddressLength {
|
||||
return nil, ErrUAddressInvalid
|
||||
}
|
||||
|
||||
A, B, err := GeneratePKPairFromUAddress(waddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u := make([]byte, 32*2*2)
|
||||
ax := math.PaddedBigBytes(A.X, 32)
|
||||
ay := math.PaddedBigBytes(A.Y, 32)
|
||||
bx := math.PaddedBigBytes(B.X, 32)
|
||||
by := math.PaddedBigBytes(B.Y, 32)
|
||||
copy(u[0:], ax[:32])
|
||||
copy(u[32:], ay[:32])
|
||||
copy(u[64:], bx[:32])
|
||||
copy(u[96:], by[:32])
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func toISO8601(t time.Time) string {
|
||||
var tz string
|
||||
name, offset := t.Zone()
|
||||
|
|
|
|||
|
|
@ -31,10 +31,13 @@ encoding may be of uneven length. The number zero encodes as "0x0".
|
|||
package hexutil
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
const uintBits = 32 << (uint64(^uint(0)) >> 63)
|
||||
|
|
@ -238,3 +241,13 @@ func mapError(err error) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PKPair2HexSlice generate byte-slice based on given public key pair
|
||||
func PKPair2HexSlice(pk1 *ecdsa.PublicKey, pk2 *ecdsa.PublicKey) []string {
|
||||
return []string{
|
||||
Encode(math.PaddedBigBytes(pk1.X, 32)),
|
||||
Encode(math.PaddedBigBytes(pk1.Y, 32)),
|
||||
Encode(math.PaddedBigBytes(pk2.X, 32)),
|
||||
Encode(math.PaddedBigBytes(pk2.Y, 32)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
|
@ -148,6 +149,20 @@ func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
|||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
|
||||
}
|
||||
|
||||
//check input error
|
||||
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
|
||||
if len(pub) != 65 {
|
||||
return nil
|
||||
}
|
||||
|
||||
x, y := elliptic.Unmarshal(S256(), pub)
|
||||
if x == nil || y == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}
|
||||
}
|
||||
|
||||
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
||||
if pub == nil || pub.X == nil || pub.Y == nil {
|
||||
return nil
|
||||
|
|
@ -219,3 +234,64 @@ func zeroBytes(bytes []byte) {
|
|||
bytes[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// A1=[hash([r]B)]G+A
|
||||
func generateA1(r []byte, A *ecdsa.PublicKey, B *ecdsa.PublicKey) ecdsa.PublicKey {
|
||||
A1 := new(ecdsa.PublicKey)
|
||||
A1.X, A1.Y = S256().ScalarMult(B.X, B.Y, r) //A1=[r]B
|
||||
A1Bytes := Keccak256(FromECDSAPub(A1)) //hash([r]B)
|
||||
A1.X, A1.Y = S256().ScalarBaseMult(A1Bytes) //[hash([r]B)]G
|
||||
A1.X, A1.Y = S256().Add(A1.X, A1.Y, A.X, A.Y) //A1=[hash([r]B)]G+A
|
||||
A1.Curve = S256()
|
||||
return *A1
|
||||
}
|
||||
|
||||
func CompareA1(b []byte, A *ecdsa.PublicKey, S1 *ecdsa.PublicKey, A1 *ecdsa.PublicKey) bool {
|
||||
A1n := generateA1(b, A, S1)
|
||||
if A1.X.Cmp(A1n.X) == 0 && A1.Y.Cmp(A1n.Y) == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// generateOneTimeKey2528 generates an OTA account for receiver using receiver's publickey
|
||||
func generateOneTimeKey2528(A *ecdsa.PublicKey, B *ecdsa.PublicKey) (A1 *ecdsa.PublicKey, R *ecdsa.PublicKey, err error) {
|
||||
RPrivateKey, err := GenerateKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
R = &RPrivateKey.PublicKey
|
||||
A1 = new(ecdsa.PublicKey)
|
||||
*A1 = generateA1(RPrivateKey.D.Bytes(), A, B)
|
||||
return A1, R, err
|
||||
}
|
||||
|
||||
// Generate OTA account interface
|
||||
func GenerateOneTimeKey(AX string, AY string, BX string, BY string) (ret []string, err error) {
|
||||
bytesAX, err := hexutil.Decode(AX)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bytesAY, err := hexutil.Decode(AY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bytesBX, err := hexutil.Decode(BX)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bytesBY, err := hexutil.Decode(BY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bnAX := new(big.Int).SetBytes(bytesAX)
|
||||
bnAY := new(big.Int).SetBytes(bytesAY)
|
||||
bnBX := new(big.Int).SetBytes(bytesBX)
|
||||
bnBY := new(big.Int).SetBytes(bytesBY)
|
||||
|
||||
pa := &ecdsa.PublicKey{X: bnAX, Y: bnAY}
|
||||
pb := &ecdsa.PublicKey{X: bnBX, Y: bnBY}
|
||||
|
||||
generatedA1, generatedR, err := generateOneTimeKey2528(pa, pb)
|
||||
return hexutil.PKPair2HexSlice(generatedA1, generatedR), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,18 @@ const (
|
|||
defaultGasPrice = params.GWei
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidUAddress = errors.New("Invalid Uaddress, try again")
|
||||
ErrFailToGeneratePKPairFromUAddress = errors.New("Fail to generate publickey pair from UAddress")
|
||||
ErrFailToGeneratePKPairSlice = errors.New("Fail to generate publickey pair hex slice")
|
||||
ErrInvalidPrivateKey = errors.New("Invalid private key")
|
||||
ErrInvalidOTAMixSet = errors.New("Invalid OTA mix set")
|
||||
ErrInvalidOTAAddr = errors.New("Invalid OTA address")
|
||||
ErrReqTooManyOTAMix = errors.New("Require too many OTA mix address")
|
||||
ErrInvalidOTAMixNum = errors.New("Invalid required OTA mix address number")
|
||||
ErrInvalidInput = errors.New("Invalid input")
|
||||
)
|
||||
|
||||
// PublicEthereumAPI provides an API to access Ethereum related information.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicEthereumAPI struct {
|
||||
|
|
@ -1822,3 +1834,41 @@ func (s *PublicTransactionPoolAPI) GetUseAddress(ctx context.Context, a common.A
|
|||
|
||||
return hexutil.Encode(useAddr[:]), nil
|
||||
}
|
||||
|
||||
// GenerateOneTimeAddress returns corresponding One-Time-Address for a given UseAddress
|
||||
func (s *PublicTransactionPoolAPI) GenerateOneTimeAddress(ctx context.Context, uAddr string) (string, error) {
|
||||
strlen := len(uAddr)
|
||||
if strlen != (common.UAddressLength<<1)+2 {
|
||||
return "", ErrInvalidUAddress
|
||||
}
|
||||
|
||||
PKBytesSlice, err := hexutil.Decode(uAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
PK1, PK2, err := keystore.GeneratePKPairFromUAddress(PKBytesSlice)
|
||||
if err != nil {
|
||||
return "", ErrFailToGeneratePKPairFromUAddress
|
||||
}
|
||||
|
||||
PKPairSlice := hexutil.PKPair2HexSlice(PK1, PK2)
|
||||
|
||||
SKOTA, err := crypto.GenerateOneTimeKey(PKPairSlice[0], PKPairSlice[1], PKPairSlice[2], PKPairSlice[3])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
otaStr := strings.Replace(strings.Join(SKOTA, ""), "0x", "", -1)
|
||||
raw, err := hexutil.Decode("0x" + otaStr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rawUanAddr, err := keystore.UaddrFromUncompressedRawBytes(raw)
|
||||
if err != nil || rawUanAddr == nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hexutil.Encode(rawUanAddr[:]), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue