Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/consensus/tendermint/apps/beacon: Breaking VRF fixes #4668

Merged
merged 4 commits into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changelog/4394.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
go/registry: Remove support for DeprecatedBeacon

The PVSS backend is no longer present in 22.x and so the field is now
removed, and even genesis registrations without a VRF signing key will
be rejected.
1 change: 1 addition & 0 deletions .changelog/4667.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/consensus/tendermint/apps/beacon: Do gas accounting earlier
5 changes: 5 additions & 0 deletions .changelog/4668.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
go/common/crypto/signature: Use ECVRF v16

The IETF draft was updated, so use the newer method of calculating proofs.
This is incompatible with the v10 proof derivation/verification, however
beta values for a given input will be identical.
2 changes: 1 addition & 1 deletion go/common/crypto/signature/signers/file/file_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func (s *Signer) Prove(alphaString []byte) ([]byte, error) {
if s.role != signature.SignerVRF {
return nil, signature.ErrInvalidRole
}
return ecvrf.Prove_v10(s.privateKey, alphaString), nil
return ecvrf.Prove(s.privateKey, alphaString), nil
}

// StaticEntropy returns PrivateKeySize bytes of cryptographic entropy that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (s *Signer) Prove(alphaString []byte) ([]byte, error) {
if s.role != signature.SignerVRF {
return nil, signature.ErrInvalidRole
}
return ecvrf.Prove_v10(s.privateKey, alphaString), nil
return ecvrf.Prove(s.privateKey, alphaString), nil
}

// StaticEntropy returns PrivateKeySize bytes of cryptographic entropy that
Expand Down
4 changes: 2 additions & 2 deletions go/common/crypto/signature/vrf_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const (
)

// VRFSigner is a Signer that also supports generating VRF proofs,
// using the semantics from v10 of the IETF Verifiable Random Functions
// using the semantics from the IETF Verifiable Random Functions
// draft.
type VRFSigner interface {
Signer
Expand Down Expand Up @@ -82,7 +82,7 @@ func (k PublicKey) VerifyVRF(alphaString, piString []byte) (bool, []byte) {
return false, nil
}

return ecvrf.Verify_v10(k[:], piString, alphaString)
return ecvrf.Verify(k[:], piString, alphaString)
}

// RawProof is a raw VRF proof.
Expand Down
4 changes: 0 additions & 4 deletions go/common/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@ type Node struct { // nolint: maligned
// based elections.
VRF *VRFInfo `json:"vrf,omitempty"`

// DeprecatedBeacon contains information for this node's
// participation in the old PVSS based random beacon protocol.
DeprecatedBeacon cbor.RawMessage `json:"beacon,omitempty"`

// Runtimes are the node's runtimes.
Runtimes []*Runtime `json:"runtimes"`

Expand Down
13 changes: 9 additions & 4 deletions go/consensus/tendermint/apps/beacon/backend_vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ func (impl *backendVRF) doProveTx(
params *beacon.ConsensusParameters,
tx *transaction.Transaction,
) error {
if err := ctx.Gas().UseGas(1, beacon.GasOpVRFProve, params.VRFParameters.GasCosts); err != nil {
return err
}

// Return early if simulating since this is just estimating gas.
if ctx.IsSimulation() {
return nil
}

vrfState, err := state.VRFState(ctx)
if err != nil {
return fmt.Errorf("beacon: failed to get VRF state: %w", err)
Expand Down Expand Up @@ -323,10 +332,6 @@ func (impl *backendVRF) doProveTx(
return nil
}

if err = ctx.Gas().UseGas(1, beacon.GasOpVRFProve, params.VRFParameters.GasCosts); err != nil {
return err
}

// Fresh proof, store pi.
vrfState.Pi[node.ID] = &proof
if err = state.SetVRFState(ctx, vrfState); err != nil {
Expand Down
5 changes: 5 additions & 0 deletions go/genesis/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func TestGenesisSanityCheck(t *testing.T) {
nodeConsensusSigner := memorySigner.NewTestSigner("node consensus genesis sanity checks signer")
nodeP2PSigner := memorySigner.NewTestSigner("node P2P genesis sanity checks signer")
nodeTLSSigner := memorySigner.NewTestSigner("node TLS genesis sanity checks signer")
nodeVRFSigner := memorySigner.NewTestSigner("node VRF genesis sanity checks signer")
validPK := signer.Public()
var validNS common.Namespace
_ = validNS.UnmarshalBinary(validPK[:])
Expand Down Expand Up @@ -258,6 +259,9 @@ func TestGenesisSanityCheck(t *testing.T) {
ID: nodeP2PSigner.Public(),
Addresses: []node.Address{testAddress},
},
VRF: &node.VRFInfo{
ID: nodeVRFSigner.Public(),
},
Consensus: node.ConsensusInfo{
ID: nodeConsensusSigner.Public(),
Addresses: []node.ConsensusAddress{testConsensusAddress},
Expand All @@ -268,6 +272,7 @@ func TestGenesisSanityCheck(t *testing.T) {
nodeP2PSigner,
nodeTLSSigner,
nodeConsensusSigner,
nodeVRFSigner,
}
signedTestNode := signNodeOrDie(nodeSigners, testNode)

Expand Down
2 changes: 1 addition & 1 deletion go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ require (
github.com/libp2p/go-libp2p v0.23.2
github.com/libp2p/go-libp2p-pubsub v0.8.1
github.com/multiformats/go-multiaddr v0.7.0
github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae
github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7
github.com/olekukonko/tablewriter v0.0.5
github.com/powerman/rpc-codec v1.2.2
Expand Down
4 changes: 2 additions & 2 deletions go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oasisprotocol/cast v0.0.0-20220606122631-eba453e69641 h1:8vZBx878kg60Z2+Amkw8vIpRcbfaAgGn59faqNZtzYw=
github.com/oasisprotocol/cast v0.0.0-20220606122631-eba453e69641/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:FatpGJD2jmJfhZiFDElaC0QhZUDQnxUeAwTGkfAHN3I=
github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17 h1:lpwUgSIAfvJJ9sQ9BB//ZCjqzzFSuSg8mYOf+8L96+E=
github.com/oasisprotocol/curve25519-voi v0.0.0-20221003100820-41fad3beba17/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661 h1:MB73kGMtuMGS+6VDoU/mitzff7Cu+aZo9ta5wabuxVA=
Expand Down
70 changes: 61 additions & 9 deletions go/oasis-node/cmd/debug/fixgenesis/fixgenesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package fixgenesis

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/spf13/viper"

"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/entity"
"github.com/oasisprotocol/oasis-core/go/common/logging"
Expand All @@ -36,6 +38,8 @@ var (
newGenesisFlag = flag.NewFlagSet("", flag.ContinueOnError)

logger = logging.GetLogger("cmd/debug/fix-genesis")

errOldNodeDesc = errors.New("deprecated node descriptor")
)

func doFixGenesis(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -104,6 +108,46 @@ func doFixGenesis(cmd *cobra.Command, args []string) {
}
}

type oldNodeDesc struct {
cbor.Versioned
ID signature.PublicKey `json:"id"`
EntityID signature.PublicKey `json:"entity_id"`
Expiration uint64 `json:"expiration"`
TLS node.TLSInfo `json:"tls"`
P2P node.P2PInfo `json:"p2p"`
Consensus node.ConsensusInfo `json:"consensus"`
VRF *node.VRFInfo `json:"vrf,omitempty"`
Runtimes []*node.Runtime `json:"runtimes"`
Roles node.RolesMask `json:"roles"`
SoftwareVersion string `json:"software_version,omitempty"`

// The CBOR decoder is extra strict and will complain if this is
// not defined, as it was removed.
DeprecatedBeacon cbor.RawMessage `json:"beacon,omitempty"`
}

func openSignedNode(context signature.Context, sn *node.MultiSignedNode) (*node.Node, error) {
var (
node node.Node
err error
)
if err = sn.Open(registry.RegisterGenesisNodeSignatureContext, &node); err == nil {
return &node, nil
}

// See if it's puking because `DeprecatedBeacon` was removed.
var oldNode oldNodeDesc
if errErr := sn.MultiSigned.Open(registry.RegisterGenesisNodeSignatureContext, &oldNode); errErr == nil {
logger.Warn("removing node as descriptor format is deprecated",
"entity_id", oldNode.EntityID,
"node_id", oldNode.ID,
)
return nil, errOldNodeDesc
}

return nil, fmt.Errorf("unable to open signed node: %w", err) // Original error
}

func updateGenesisDoc(oldDoc genesis.Document) (*genesis.Document, error) {
// Create the new genesis document template.
newDoc := oldDoc
Expand Down Expand Up @@ -142,11 +186,15 @@ func updateGenesisDoc(oldDoc genesis.Document) (*genesis.Document, error) {
entities = append(entities, &entity)
}
for _, sigNode := range oldDoc.Registry.Nodes {
var node node.Node
if err = sigNode.Open(registry.RegisterGenesisNodeSignatureContext, &node); err != nil {
return nil, fmt.Errorf("unable to open signed node: %w", err)
var node *node.Node
node, err = openSignedNode(registry.RegisterGenesisNodeSignatureContext, sigNode)
if err != nil {
if errors.Is(err, errOldNodeDesc) {
continue
}
return nil, err
}
nodes = append(nodes, &node)
nodes = append(nodes, node)
}
runtimes = append(runtimes, newDoc.Registry.Runtimes...)
runtimes = append(runtimes, newDoc.Registry.SuspendedRuntimes...)
Expand All @@ -166,7 +214,7 @@ func updateGenesisDoc(oldDoc genesis.Document) (*genesis.Document, error) {
entityMap := make(map[signature.PublicKey]*entity.Entity)
for _, sigEntity := range oldDoc.Registry.Entities {
var entity entity.Entity
if err := sigEntity.Open(registry.RegisterEntitySignatureContext, &entity); err != nil {
if err = sigEntity.Open(registry.RegisterEntitySignatureContext, &entity); err != nil {
return nil, fmt.Errorf("unable to open signed entity: %w", err)
}
addr := staking.NewAddress(entity.ID)
Expand All @@ -180,7 +228,7 @@ func updateGenesisDoc(oldDoc genesis.Document) (*genesis.Document, error) {
continue
}

if err := escrowAcc.CheckStakeClaims(newDoc.Staking.Parameters.Thresholds); err != nil {
if err = escrowAcc.CheckStakeClaims(newDoc.Staking.Parameters.Thresholds); err != nil {
logger.Warn("removing entity not passing stake claims",
"entity_id", entity.ID,
"err", err,
Expand All @@ -193,9 +241,13 @@ func updateGenesisDoc(oldDoc genesis.Document) (*genesis.Document, error) {
}
NodeLoop:
for _, sigNode := range oldDoc.Registry.Nodes {
var node node.Node
if err := sigNode.Open(registry.RegisterGenesisNodeSignatureContext, &node); err != nil {
return nil, fmt.Errorf("unable to open signed node: %w", err)
var node *node.Node
node, err = openSignedNode(registry.RegisterGenesisNodeSignatureContext, sigNode)
if err != nil {
if errors.Is(err, errOldNodeDesc) {
continue
}
return nil, err
}
if ent := removedEntities[node.EntityID]; ent != nil {
logger.Warn("removing node as owning entity doesn't pass stake claims",
Expand Down
2 changes: 1 addition & 1 deletion go/oasis-test-runner/scenario/e2e/genesis_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const (
latestMainnetGenesisURL = "https://github.com/oasisprotocol/mainnet-artifacts/releases/download/2022-04-11/genesis.json"
latestMainnetGenesisDocumentHash = "b11b369e0da5bb230b220127f5e7b242d385ef8c6f54906243f30af63c815535"

latestMainnetNeedsUpgrade = false
latestMainnetNeedsUpgrade = true
)

// GenesisFile is the scenario for testing the correctness of marshalled genesis
Expand Down
19 changes: 3 additions & 16 deletions go/registry/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ func VerifyRegisterNodeArgs( // nolint: gocyclo
return nil, nil, err
}

// Validate VRFInfo, DeprecatedBeacon.
// Validate VRFInfo.
if n.VRF != nil {
if !sigNode.MultiSigned.IsSignedBy(n.VRF.ID) {
logger.Error("RegisterNode: not signed by VRF ID",
Expand All @@ -655,21 +655,8 @@ func VerifyRegisterNodeArgs( // nolint: gocyclo
return nil, nil, fmt.Errorf("%w: registration not signed by VRF ID", ErrInvalidArgument)
}
expectedSigners = append(expectedSigners, n.VRF.ID)
}
switch isGenesis {
case true:
// Allow legacy entries without a VRF public key, and with the old PVSS
// curve point to be in the genesis document, to ease transition.
//
// All new (re)registrations will require a VRF public key, and reject
// descriptors with the old PVSS curve point.
case false:
if n.VRF == nil {
return nil, nil, fmt.Errorf("%w: registration missing VRF ID", ErrInvalidArgument)
}
if n.DeprecatedBeacon != nil {
return nil, nil, fmt.Errorf("%w: registration contains deprecated PVSS field", ErrInvalidArgument)
}
} else {
return nil, nil, fmt.Errorf("%w: registration missing VRF ID", ErrInvalidArgument)
}

// Validate TLSInfo.
Expand Down