prysm-pulse/validator/keymanager/derived/v1derivation/util.go
Raul Jordan a81c863ddb
Rename Accounts-V2 to Accounts (#7545)
* rename accounts v2

* rename keymanager and fix imports

* rename accounts-v2 instances

* imports

* build

* build fix

* deepsource

* fix up broken aliases

* imports

* gaz

* Update validator/accounts/accounts_import_test.go

Co-authored-by: Ivan Martinez <ivanthegreatdev@gmail.com>

* fmt

Co-authored-by: Ivan Martinez <ivanthegreatdev@gmail.com>
2020-10-15 22:31:52 +00:00

179 lines
5.2 KiB
Go

// Copyright 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1derivation
import (
"crypto/sha256"
"fmt"
"math/big"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/wealdtech/go-bytesutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
"golang.org/x/crypto/hkdf"
)
func _bigInt(input string) *big.Int {
result, _ := new(big.Int).SetString(input, 10)
return result
}
var (
r = _bigInt("52435875175126190479447740508185965837690552500527637822603658699938581184513")
// 48 comes from ceil((1.5 * ceil(log2(r))) / 8)
l = 48
)
// PrivateKeyFromSeedAndPath generates a private key given a seed and a path.
// Follows ERC-2334.
func PrivateKeyFromSeedAndPath(seed []byte, path string) (*e2types.BLSPrivateKey, error) {
if path == "" {
return nil, errors.New("no path")
}
if len(seed) < 16 {
return nil, errors.New("seed must be at least 128 bits")
}
pathBits := strings.Split(path, "/")
var sk *big.Int
var err error
for i := range pathBits {
if pathBits[i] == "" {
return nil, fmt.Errorf("no entry at path component %d", i)
}
if pathBits[i] == "m" {
if i != 0 {
return nil, fmt.Errorf("invalid master at path component %d", i)
}
sk, err = DeriveMasterSK(seed)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate master key at path component %d", i)
}
} else {
if i == 0 {
return nil, fmt.Errorf("not master at path component %d", i)
}
index, err := strconv.ParseInt(pathBits[i], 10, 32)
if err != nil || index < 0 {
return nil, fmt.Errorf("invalid index %q at path component %d", pathBits[i], i)
}
sk, err = DeriveChildSK(sk, uint32(index))
if err != nil {
return nil, errors.Wrapf(err, "failed to derive child SK at path component %d", i)
}
}
}
// SK can be shorter than 32 bytes so left-pad it here.
bytes := make([]byte, 32)
skBytes := sk.Bytes()
copy(bytes[32-len(skBytes):], skBytes)
return e2types.BLSPrivateKeyFromBytes(bytes)
}
// DeriveMasterSK derives the master secret key from a seed.
// Follows ERC-2333.
func DeriveMasterSK(seed []byte) (*big.Int, error) {
if len(seed) < 16 {
return nil, errors.New("seed must be at least 128 bits")
}
return hkdfModR(seed, "")
}
// DeriveChildSK derives the child secret key from a parent key.
// Follows ERC-2333.
func DeriveChildSK(parentSK *big.Int, index uint32) (*big.Int, error) {
pk, err := parentSKToLamportPK(parentSK, index)
if err != nil {
return nil, err
}
return hkdfModR(pk, "")
}
// ikmToLamportSK creates a Lamport secret key.
func ikmToLamportSK(ikm, salt []byte) ([255][32]byte, error) {
prk := hkdf.Extract(sha256.New, ikm, salt)
okm := hkdf.Expand(sha256.New, prk, nil)
var lamportSK [255][32]byte
for i := 0; i < 255; i++ {
var result [32]byte
read, err := okm.Read(result[:])
if err != nil {
return lamportSK, err
}
if read != 32 {
return lamportSK, fmt.Errorf("only read %d bytes", read)
}
lamportSK[i] = result
}
return lamportSK, nil
}
// parentSKToLamportPK generates the Lamport private key from a BLS secret key.
func parentSKToLamportPK(parentSK *big.Int, index uint32) ([]byte, error) {
salt := i2OSP(big.NewInt(int64(index)), 4)
ikm := i2OSP(parentSK, 32)
lamport0, err := ikmToLamportSK(ikm, salt)
if err != nil {
return nil, err
}
notIKM := bytesutil.XOR(ikm)
lamport1, err := ikmToLamportSK(notIKM, salt)
if err != nil {
return nil, err
}
lamportPK := make([]byte, (255+255)*32)
for i := 0; i < 255; i++ {
h := hashutil.Hash(lamport0[i][:])
copy(lamportPK[32*i:], h[:])
}
for i := 0; i < 255; i++ {
h := hashutil.Hash(lamport1[i][:])
copy(lamportPK[(i+255)*32:], h[:])
}
compressedLamportPK := hashutil.Hash(lamportPK)
return compressedLamportPK[:], nil
}
// hkdfModR hashes 32 random bytes into the subgroup of the BLS12-381 private keys.
func hkdfModR(ikm []byte, keyInfo string) (*big.Int, error) {
prk := hkdf.Extract(sha256.New, append(ikm, i2OSP(big.NewInt(0), 1)...), []byte("BLS-SIG-KEYGEN-SALT-"))
okm := hkdf.Expand(sha256.New, prk, append([]byte(keyInfo), i2OSP(big.NewInt(int64(l)), 2)...))
okmOut := make([]byte, l)
read, err := okm.Read(okmOut)
if err != nil {
return nil, err
}
if read != l {
return nil, fmt.Errorf("only read %d bytes", read)
}
return new(big.Int).Mod(osToIP(okmOut), r), nil
}
// osToIP turns a byte array in to an integer as per https://ietf.org/rfc/rfc3447.txt
func osToIP(data []byte) *big.Int {
return new(big.Int).SetBytes(data)
}
// i2OSP turns an integer in to a byte array as per https://ietf.org/rfc/rfc3447.txt
func i2OSP(data *big.Int, resLen int) []byte {
res := make([]byte, resLen)
bytes := data.Bytes()
copy(res[resLen-len(bytes):], bytes)
return res
}