Skip to content

Commit

Permalink
Merge pull request #256 from spacemeshos/distributed-post-verification
Browse files Browse the repository at this point in the history
Distributed verification
  • Loading branch information
poszu authored Jan 31, 2024
2 parents a09cf87 + f559650 commit 7925759
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 194 deletions.
2 changes: 1 addition & 1 deletion Makefile.Inc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ else
endif

# Also update 'SUPPORTED_VERSION' in internal/postrs/version_check.go
POSTRS_SETUP_REV = 0.6.6
POSTRS_SETUP_REV = 0.7.0
POSTRS_SETUP_ZIP = libpost-$(platform)-v$(POSTRS_SETUP_REV).zip
POSTRS_SETUP_URL_ZIP ?= https://github.com/spacemeshos/post-rs/releases/download/v$(POSTRS_SETUP_REV)/$(POSTRS_SETUP_ZIP)
ifeq ($(platform), windows)
Expand Down
2 changes: 1 addition & 1 deletion cmd/postcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ func main() {
log.Fatalln("failed to create verifier", err)
}
defer verifier.Close()
err = verifier.Verify(proof, proofMetadata, cfg, logger, verifying.WithLabelScryptParams(opts.Scrypt))
err = verifier.Verify(proof, proofMetadata, cfg, logger, verifying.WithLabelScryptParams(opts.Scrypt), verifying.AllIndices())
if err != nil {
log.Fatalln("failed to verify test proof", err)
}
Expand Down
2 changes: 0 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ func MainnetConfig() Config {
LabelsPerUnit: 4294967296, // 64GiB units
K1: 26,
K2: 37,
K3: 37,
}
_, err := hex.Decode(cfg.PowDifficulty[:], []byte("000dfb23b0979b4b000000000000000000000000000000000000000000000000"))
if err != nil {
Expand All @@ -100,7 +99,6 @@ func DefaultConfig() Config {
LabelsPerUnit: 512, // 8kB units
K1: 26,
K2: 37,
K3: 37,
}
for i := range cfg.PowDifficulty {
cfg.PowDifficulty[i] = 0xFF
Expand Down
18 changes: 9 additions & 9 deletions internal/postrs/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type DeviceClass int

const (
ClassUnspecified = 0
ClassCPU = DeviceClass((C.DeviceClass)(C.CPU))
ClassGPU = DeviceClass((C.DeviceClass)(C.GPU))
ClassCPU = DeviceClass((C.DeviceClass)(C.DeviceClass_CPU))
ClassGPU = DeviceClass((C.DeviceClass)(C.DeviceClass_GPU))
)

// Provider is a struct that contains information about an OpenCL provider.
Expand Down Expand Up @@ -60,17 +60,17 @@ const (
// InitResultToError converts the return value of the C.initialize() function to a Go error.
func InitResultToError(retVal uint32) error {
switch retVal {
case C.InitializeOk:
case C.InitializeResult_Ok:
return nil
case C.InitializeOkNonceNotFound:
case C.InitializeResult_OkNonceNotFound:
return nil
case C.InitializeInvalidLabelsRange:
case C.InitializeResult_InvalidLabelsRange:
return ErrInvalidLabelsRange
case C.InitializeError:
case C.InitializeResult_Error:
return ErrInitializationFailed
case C.InitializeInvalidArgument:
case C.InitializeResult_InvalidArgument:
return ErrInvalidArgument
case C.InitializeFailedToGetProviders:
case C.InitializeResult_FailedToGetProviders:
return ErrFetchProviders
default:
return ErrUnknown
Expand Down Expand Up @@ -121,7 +121,7 @@ func cScryptPositions(init *C.Initializer, opt *option, start, end uint64) ([]by

output := C.GoBytes(cOut, C.int(cOutputSize))

if retVal == C.InitializeOkNonceNotFound {
if retVal == C.InitializeResult_OkNonceNotFound {
return output, nil, nil
}

Expand Down
24 changes: 12 additions & 12 deletions internal/postrs/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ var (
oncer sync.Once

levelMap = map[zapcore.Level]C.Level{
zapcore.DebugLevel: C.Trace,
zapcore.InfoLevel: C.Info,
zapcore.WarnLevel: C.Warn,
zapcore.ErrorLevel: C.Error,
zapcore.DPanicLevel: C.Error,
zapcore.PanicLevel: C.Error,
zapcore.FatalLevel: C.Error,
zapcore.DebugLevel: C.Level_Trace,
zapcore.InfoLevel: C.Level_Info,
zapcore.WarnLevel: C.Level_Warn,
zapcore.ErrorLevel: C.Level_Error,
zapcore.DPanicLevel: C.Level_Error,
zapcore.PanicLevel: C.Level_Error,
zapcore.FatalLevel: C.Level_Error,
}

zapLevelMap = map[C.Level]zapcore.Level{
C.Error: zapcore.ErrorLevel,
C.Warn: zapcore.WarnLevel,
C.Info: zapcore.InfoLevel,
C.Debug: zapcore.DebugLevel,
C.Trace: zapcore.DebugLevel,
C.Level_Error: zapcore.ErrorLevel,
C.Level_Warn: zapcore.WarnLevel,
C.Level_Info: zapcore.InfoLevel,
C.Level_Debug: zapcore.DebugLevel,
C.Level_Trace: zapcore.DebugLevel,
}
)

Expand Down
21 changes: 16 additions & 5 deletions internal/postrs/pos_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "C"

import (
"errors"
"fmt"
"unsafe"

"go.uber.org/zap"
Expand Down Expand Up @@ -70,14 +71,24 @@ func VerifyPos(dataDir string, scryptParams ScryptParams, o ...VerifyPosOptionsF
defer C.free(unsafe.Pointer(dataDirPtr))

result := C.verify_pos(dataDirPtr, (*C.uint32_t)(opts.fromFile), (*C.uint32_t)(opts.toFile), C.double(opts.fraction), scryptParams)
switch result {
case C.Ok:
switch result.tag {
case C.VerifyResult_Ok:
return nil
case C.Invalid:
return ErrInvalidPos
case C.InvalidArgument:
case C.VerifyResult_Invalid:
result := castBytes[C.VerifyPosResult_Invalid_Body](result.anon0[:])
return fmt.Errorf("%w: file %d contains invalid label at offset %d", ErrInvalidPos, result.file, result.offset)
case C.VerifyResult_InvalidArgument:
return ErrInvalidArgument
default:
return ErrUnknown
}
}

// cast bytes to a pointer of type T
func castBytes[T any](body []byte) *T {
var v T
if len(body) < int(unsafe.Sizeof(v)) {
panic("invalid size")
}
return (*T)(unsafe.Pointer(&body[0]))
}
126 changes: 100 additions & 26 deletions internal/postrs/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package postrs
import "C"

import (
"encoding/hex"
"errors"
"fmt"
"sync"
Expand All @@ -24,9 +23,8 @@ type Config struct {
MaxNumUnits uint32
LabelsPerUnit uint64

K1 uint32 // K1 specifies the difficulty for a label to be a candidate for a proof.
K2 uint32 // K2 is the number of labels below the required difficulty required for a proof.
K3 uint32 // K3 is the size of the subset of proof indices that is validated.
K1 uint // K1 specifies the difficulty for a label to be a candidate for a proof.
K2 uint // K2 is the number of labels below the required difficulty required for a proof.

PowDifficulty [32]byte
}
Expand All @@ -39,16 +37,10 @@ func NewScryptParams(n, r, p uint) ScryptParams {
}
}

type HexEncoded []byte

func (h HexEncoded) String() string {
return hex.EncodeToString(h)
}

// ErrVerifierClosed is returned when calling a method on an already closed Scrypt instance.
var ErrVerifierClosed = errors.New("verifier has been closed")

func GenerateProof(dataDir string, challenge []byte, logger *zap.Logger, nonces, threads uint, K1, K2 uint32, powDifficulty [32]byte, powFlags PowFlags) (*shared.Proof, error) {
func GenerateProof(dataDir string, challenge []byte, logger *zap.Logger, nonces, threads, K1, K2 uint, powDifficulty [32]byte, powFlags PowFlags) (*shared.Proof, error) {
if logger != nil {
setLogCallback(logger)
}
Expand Down Expand Up @@ -134,7 +126,7 @@ type Verifier struct {
func NewVerifier(powFlags PowFlags) (*Verifier, error) {
verifier := Verifier{}
result := C.new_verifier(powFlags, &verifier.inner)
if result != C.Ok {
if result != C.VerifyResult_Ok {
return nil, fmt.Errorf("failed to create verifier")
}
return &verifier, nil
Expand All @@ -152,7 +144,48 @@ func (v *Verifier) Close() error {
return nil
}

func (v *Verifier) VerifyProof(proof *shared.Proof, metadata *shared.ProofMetadata, logger *zap.Logger, cfg Config, scryptParams ScryptParams) error {
type verifyOptions struct {
// one of verifyAllT, verifySubsetT, verifyOneT
mode any
}

type verifyAllT struct{}

type verifySubsetT struct {
k3 uint
seed []byte
}

type verifyOneT struct {
ord int
}

type VerifyOptionFunc func(*verifyOptions)

// Verify all indices in the proof.
func VerifyAll() VerifyOptionFunc {
return func(o *verifyOptions) {
o.mode = verifyAllT{}
}
}

// Verify only the selected index.
// The `ord` is the ordinal number of the index in the proof to verify.
func VerifyOne(ord int) VerifyOptionFunc {
return func(o *verifyOptions) {
o.mode = verifyOneT{ord: ord}
}
}

// Verify a subset of randomly selected K3 indices.
// The `seed` is used to randomize the selection of indices.
func VerifySubset(k3 uint, seed []byte) VerifyOptionFunc {
return func(o *verifyOptions) {
o.mode = verifySubsetT{k3: k3, seed: seed}
}
}

func (v *Verifier) VerifyProof(proof *shared.Proof, metadata *shared.ProofMetadata, logger *zap.Logger, cfg Config, scryptParams ScryptParams, opts ...VerifyOptionFunc) error {
if logger != nil {
setLogCallback(logger)
}
Expand All @@ -179,7 +212,6 @@ func (v *Verifier) VerifyProof(proof *shared.Proof, metadata *shared.ProofMetada
config := C.ProofConfig{
k1: C.uint32_t(cfg.K1),
k2: C.uint32_t(cfg.K2),
k3: C.uint32_t(cfg.K3),
}
for i, b := range cfg.PowDifficulty {
config.pow_difficulty[i] = C.uchar(b)
Expand Down Expand Up @@ -214,22 +246,64 @@ func (v *Verifier) VerifyProof(proof *shared.Proof, metadata *shared.ProofMetada
return ErrVerifierClosed
}

result := C.verify_proof(
v.inner,
cProof,
&cMetadata,
config,
initConfig,
)
options := verifyOptions{
mode: verifyAllT{},
}
for _, opt := range opts {
opt(&options)
}

var result C.VerifyResult
switch t := options.mode.(type) {
case verifyAllT:
result = C.verify_proof(
v.inner,
cProof,
&cMetadata,
config,
initConfig,
)
case verifySubsetT:
seed := C.CBytes(t.seed)
defer C.free(seed)
result = C.verify_proof_subset(
v.inner,
cProof,
&cMetadata,
config,
initConfig,
C.size_t(t.k3),
(*C.uchar)(seed),
C.size_t(len(t.seed)),
)
case verifyOneT:
result = C.verify_proof_index(
v.inner,
cProof,
&cMetadata,
config,
initConfig,
C.size_t(t.ord),
)
}

switch result {
case C.Ok:
switch result.tag {
case C.VerifyResult_Ok:
return nil
case C.Invalid:
return fmt.Errorf("invalid proof")
case C.InvalidArgument:
case C.VerifyResult_InvalidIndex:
result := castBytes[C.VerifyResult_InvalidIndex_Body](result.anon0[:])
return &ErrInvalidIndex{Index: int(result.index_id)}
case C.VerifyResult_InvalidArgument:
return fmt.Errorf("invalid argument")
default:
return fmt.Errorf("unknown error")
}
}

type ErrInvalidIndex struct {
Index int
}

func (e ErrInvalidIndex) Error() string {
return fmt.Sprintf("invalid index: %d", e.Index)
}
2 changes: 1 addition & 1 deletion internal/postrs/version_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

const (
// regexp matching supported versions of post-rs library
SUPPORTED_VERSION = `0\.6\.([5-9]|[1-9][0-9]+)` // 0.6.5+
SUPPORTED_VERSION = `0\.7\.(\d+)` // 0.7.*
// Set this env variable to "true" or "1" to disable version check.
DISABLE_CKECK_ENV = "LIBPOST_DISABLE_VERSION_CHECK"
)
Expand Down
7 changes: 7 additions & 0 deletions proving/proving_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ func WithPowFlags(flags config.PowFlags) OptionFunc {
}
}

func LightMode() OptionFunc {
return func(o *option) error {
o.powFlags = config.RecommendedPowFlags()
return nil
}
}

func WithNonces(nonces uint) OptionFunc {
return func(o *option) error {
if nonces == 0 {
Expand Down
Loading

0 comments on commit 7925759

Please sign in to comment.