mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
DepositInput: Proof of possession, withdrawal credentials (#1675)
* move deposit input to keystore pkg, add proof of possession and withdrawal addr * Add spec details for deposit input * Use ssz * actually use withdrawal key
This commit is contained in:
committed by
Raul Jordan
parent
6bb2d32ad0
commit
273993a7e0
@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"deposit_input.go",
|
||||
"keccak256.go",
|
||||
"key.go",
|
||||
"keystore.go",
|
||||
@@ -11,7 +12,10 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/shared/keystore",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/ssz:go_default_library",
|
||||
"@com_github_pborman_uuid//:go_default_library",
|
||||
"@org_golang_x_crypto//pbkdf2:go_default_library",
|
||||
"@org_golang_x_crypto//scrypt:go_default_library",
|
||||
@@ -22,14 +26,19 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"deposit_input_test.go",
|
||||
"key_test.go",
|
||||
"keystore_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/ssz:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_pborman_uuid//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
51
shared/keystore/deposit_input.go
Normal file
51
shared/keystore/deposit_input.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package keystore
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/ssz"
|
||||
)
|
||||
|
||||
// DepositInput for a given key. This input data can be used to when making a
|
||||
// validator deposit. The input data includes a proof of possession field
|
||||
// signed by the deposit key.
|
||||
//
|
||||
// Spec details about general deposit workflow:
|
||||
// To submit a deposit:
|
||||
//
|
||||
// - Pack the validator's initialization parameters into deposit_input, a DepositInput SSZ object.
|
||||
// - Set deposit_input.proof_of_possession = EMPTY_SIGNATURE.
|
||||
// - Let proof_of_possession be the result of bls_sign of the hash_tree_root(deposit_input) with domain=DOMAIN_DEPOSIT.
|
||||
// - Set deposit_input.proof_of_possession = proof_of_possession.
|
||||
// - Let amount be the amount in Gwei to be deposited by the validator where MIN_DEPOSIT_AMOUNT <= amount <= MAX_DEPOSIT_AMOUNT.
|
||||
// - Send a transaction on the Ethereum 1.0 chain to DEPOSIT_CONTRACT_ADDRESS executing deposit along with serialize(deposit_input) as the singular bytes input along with a deposit amount in Gwei.
|
||||
//
|
||||
// See: https://github.com/ethereum/eth2.0-specs/blob/dev/specs/validator/0_beacon-chain-validator.md#submit-deposit
|
||||
func DepositInput(depositKey *Key, withdrawalKey *Key) (*pb.DepositInput, error) {
|
||||
di := &pb.DepositInput{
|
||||
Pubkey: depositKey.PublicKey.Marshal(),
|
||||
WithdrawalCredentialsHash32: withdrawalCredentialsHash(withdrawalKey),
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := ssz.Encode(buf, di); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
di.ProofOfPossession = depositKey.SecretKey.Sign(buf.Bytes(), params.BeaconConfig().DomainDeposit).Marshal()
|
||||
|
||||
return di, nil
|
||||
}
|
||||
|
||||
// withdrawalCredentialsHash forms a 32 byte hash of the withdrawal public
|
||||
// address.
|
||||
//
|
||||
// The specification is as follows:
|
||||
// withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE
|
||||
// withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]
|
||||
// where withdrawal_credentials is of type bytes32.
|
||||
func withdrawalCredentialsHash(withdrawalKey *Key) []byte {
|
||||
h := Keccak256(withdrawalKey.PublicKey.Marshal())
|
||||
return append([]byte{params.BeaconConfig().BLSWithdrawalPrefixByte}, h...)[:32]
|
||||
}
|
||||
50
shared/keystore/deposit_input_test.go
Normal file
50
shared/keystore/deposit_input_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package keystore_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/keystore"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/ssz"
|
||||
)
|
||||
|
||||
func TestDepositInput_GeneratesPb(t *testing.T) {
|
||||
k1, err := keystore.NewKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
k2, err := keystore.NewKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
result, err := keystore.DepositInput(k1, k2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(result.Pubkey, k1.PublicKey.Marshal()) {
|
||||
t.Errorf("Mismatched pubkeys in deposit input. Want = %x, got = %x", result.Pubkey, k1.PublicKey.Marshal())
|
||||
}
|
||||
|
||||
sig, err := bls.SignatureFromBytes(result.ProofOfPossession)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify that the proof of possession is a signed copy of the input data.
|
||||
proofOfPossessionInputPb := proto.Clone(result).(*pb.DepositInput)
|
||||
proofOfPossessionInputPb.ProofOfPossession = nil
|
||||
buf := new(bytes.Buffer)
|
||||
if err := ssz.Encode(buf, proofOfPossessionInputPb); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !sig.Verify(buf.Bytes(), k1.PublicKey, params.BeaconConfig().DomainDeposit) {
|
||||
t.Error("Invalid proof of proofOfPossession signature")
|
||||
}
|
||||
}
|
||||
@@ -129,13 +129,14 @@ var defaultBeaconConfig = &BeaconChainConfig{
|
||||
ForkChoiceBalanceIncrement: 1 * 1e9,
|
||||
|
||||
// Initial value constants.
|
||||
GenesisForkVersion: 0,
|
||||
GenesisSlot: 1 << 63,
|
||||
GenesisEpoch: 1 << 63 / 64,
|
||||
GenesisStartShard: 0,
|
||||
FarFutureEpoch: 1<<64 - 1,
|
||||
ZeroHash: [32]byte{},
|
||||
EmptySignature: [96]byte{},
|
||||
GenesisForkVersion: 0,
|
||||
GenesisSlot: 1 << 63,
|
||||
GenesisEpoch: 1 << 63 / 64,
|
||||
GenesisStartShard: 0,
|
||||
FarFutureEpoch: 1<<64 - 1,
|
||||
ZeroHash: [32]byte{},
|
||||
EmptySignature: [96]byte{},
|
||||
BLSWithdrawalPrefixByte: byte(0),
|
||||
|
||||
// Time parameter constants.
|
||||
SecondsPerSlot: 6,
|
||||
|
||||
@@ -6,7 +6,6 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/validator/accounts",
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/keystore:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/ssz:go_default_library",
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/keystore"
|
||||
"github.com/prysmaticlabs/prysm/shared/ssz"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -73,12 +72,10 @@ func NewValidatorAccount(directory string, password string) error {
|
||||
validatorKeyFile,
|
||||
).Info("Keystore generated for validator signatures at path")
|
||||
|
||||
data := &pb.DepositInput{
|
||||
Pubkey: validatorKey.SecretKey.PublicKey().Marshal(),
|
||||
ProofOfPossession: []byte("pop"),
|
||||
WithdrawalCredentialsHash32: []byte("withdraw"),
|
||||
data, err := keystore.DepositInput(validatorKey, shardWithdrawalKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to generate deposit data: %v", err)
|
||||
}
|
||||
|
||||
serializedData := new(bytes.Buffer)
|
||||
if err := ssz.Encode(serializedData, data); err != nil {
|
||||
return fmt.Errorf("could not serialize deposit data: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user