diff --git a/.gitignore b/.gitignore index 7b51df2dd..cbf0165f3 100644 --- a/.gitignore +++ b/.gitignore @@ -52,5 +52,5 @@ test/fuzz/**/corpus test/fuzz/**/crashers test/fuzz/**/suppressions test/fuzz/**/*.zip -crypto/vrf/internal/vrf/lib -crypto/vrf/internal/vrf/include +node/data +crypto/vrf/internal/vrf/sodium diff --git a/Makefile b/Makefile index 87609575e..6ca65237b 100644 --- a/Makefile +++ b/Makefile @@ -3,26 +3,20 @@ SRCPATH=$(shell pwd) OUTPUT?=build/ostracon INCLUDE = -I=${GOPATH}/src/github.com/line/ostracon -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protobuf -BUILD_TAGS?='ostracon' +BUILD_TAGS?=ostracon VERSION := $(shell git describe --always) -CGO_OPTPTION=0 LIBSODIUM_TARGET= -PREPARE_LIBSODIUM_TARGET= ifeq ($(LIBSODIUM), 1) - BUILD_TAGS='libsodium ostracon' LIBSODIUM_TARGET=libsodium -ifneq ($(OS), Windows_NT) -ifeq ($(shell uname -s), Linux) - PREPARE_LIBSODIUM_TARGET=prepare-libsodium-linux + BUILD_TAGS += libsodium endif -endif -endif -LIBSODIM_BUILD_TAGS='libsodium ostracon' LD_FLAGS = -X github.com/line/ostracon/version.Version=$(VERSION) BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)" HTTPS_GIT := https://github.com/line/ostracon.git DOCKER_BUF := docker run -v $(shell pwd):/workspace --workdir /workspace bufbuild/buf CGO_ENABLED ?= 0 +TARGET_OS ?= $(shell go env GOOS) +TARGET_ARCH ?= $(shell go env GOARCH) # handle nostrip ifeq (,$(findstring nostrip,$(OSTRACON_BUILD_OPTIONS))) @@ -72,7 +66,7 @@ build: $(LIBSODIUM_TARGET) CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags "$(BUILD_TAGS)" -o $(OUTPUT) ./cmd/ostracon/ .PHONY: build -install: +install: $(LIBSODIUM_TARGET) CGO_ENABLED=1 go install $(BUILD_FLAGS) -tags "$(BUILD_TAGS)" ./cmd/ostracon .PHONY: install @@ -151,15 +145,21 @@ install_abci: ######################################## ### libsodium -prepare-libsodium-linux: - apt-get update && apt-get -y install libtool libboost-all-dev autoconf build-essential +VRF_ROOT = $(SRCPATH)/crypto/vrf/internal/vrf +LIBSODIUM_ROOT = $(VRF_ROOT)/libsodium +LIBSODIUM_OS = $(VRF_ROOT)/sodium/$(TARGET_OS)_$(TARGET_ARCH) libsodium: - cd $(SRCPATH)/crypto/vrf/internal/vrf/libsodium && \ - ./autogen.sh && \ - ./configure --disable-shared --prefix="$(SRCPATH)/crypto/vrf/internal/vrf/" && \ - $(MAKE) && \ - $(MAKE) install + rm -rf $(LIBSODIUM_ROOT) + mkdir $(LIBSODIUM_ROOT) + git submodule update --init --recursive + @if [ ! -f $(LIBSODIUM_OS)/lib/libsodium.a ]; then \ + cd $(LIBSODIUM_ROOT) && \ + ./autogen.sh && \ + ./configure --disable-shared --prefix="$(LIBSODIUM_OS)" && \ + $(MAKE) && \ + $(MAKE) install; \ + fi ######################################## ### Distribution @@ -287,9 +287,9 @@ DOCKER_CMD = docker run --rm \ -v `pwd`:$(DOCKER_HOME) \ -w $(DOCKER_HOME) DOCKER_IMG = golang:1.15-alpine -BUILD_CMD = apk add --update --no-cache git make gcc libc-dev build-base curl jq file gmp-dev clang \ +BUILD_CMD = apk add --update --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang libtool autoconf automake \ && cd $(DOCKER_HOME) \ - && make build-linux + && LIBSODIUM=$(LIBSODIUM) make build-linux # Login docker-container for confirmation building linux binary build-shell: diff --git a/README.md b/README.md index 4cc878dfd..e1cc02a85 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,25 @@ Ostracon is forked from Tendermint Core at 2021-03-15. # Quick Start +## git clone +```shell +git clone https://github.com/line/ostracon.git +# or +git clone git@github.com:line/ostracon.git +``` + +### git clone with recursive if you want to use libsodium +```shell +git clone --recursive https://github.com/line/ostracon.git +# or +git clone --recursive git@github.com:line/ostracon.git +``` + +### git submodule if you forget to clone with submodule +```shell +git submodule update --init --recursive +``` + ## Local Standalone **Build** ```sh diff --git a/crypto/composite/composite.go b/crypto/composite/composite.go index 59da4b556..de1fe40cd 100644 --- a/crypto/composite/composite.go +++ b/crypto/composite/composite.go @@ -92,9 +92,9 @@ func (sk PrivKey) Sign(msg []byte) ([]byte, error) { return sk.SignKey.Sign(msg) } -// VRFProve generates a VRF Proof for given seed to generate a verifiable random. -func (sk PrivKey) VRFProve(seed []byte) (crypto.Proof, error) { - return sk.VrfKey.VRFProve(seed) +// VRFProve generates a VRF Proof for given message to generate a verifiable random. +func (sk PrivKey) VRFProve(message []byte) (crypto.Proof, error) { + return sk.VrfKey.VRFProve(message) } func (sk PrivKey) PubKey() crypto.PubKey { diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index f63c33682..1a94bfbbc 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -3,6 +3,7 @@ package ed25519 import ( "bytes" "crypto/subtle" + "encoding/hex" "fmt" "io" @@ -60,9 +61,9 @@ func (privKey PrivKey) Sign(msg []byte) ([]byte, error) { return signatureBytes, nil } -// VRFProve generates a VRF Proof for given seed to generate a verifiable random. -func (privKey PrivKey) VRFProve(seed []byte) (crypto.Proof, error) { - proof, err := vrf.Prove(privKey[:], seed) +// VRFProve generates a VRF Proof for given message to generate a verifiable random. +func (privKey PrivKey) VRFProve(message []byte) (crypto.Proof, error) { + proof, err := vrf.Prove(privKey[:], message) if err != nil { return nil, err } @@ -172,14 +173,15 @@ func (pubKey PubKey) Type() string { return KeyType } -// VRFVerify verifies that the given VRF Proof was generated from the seed by the owner of this public key. -func (pubKey PubKey) VRFVerify(proof crypto.Proof, seed []byte) (crypto.Output, error) { - valid, err := vrf.Verify(pubKey[:], vrf.Proof(proof), seed) +// VRFVerify verifies that the given VRF Proof was generated from the message by the owner of this public key. +func (pubKey PubKey) VRFVerify(proof crypto.Proof, message []byte) (crypto.Output, error) { + valid, err := vrf.Verify(pubKey[:], vrf.Proof(proof), message) if err != nil { - return nil, fmt.Errorf("the specified proof is not a valid ed25519 proof: %v", proof) + return nil, fmt.Errorf("the specified proof is not a valid ed25519 proof: err: %s", err.Error()) } if !valid { - return nil, fmt.Errorf("the specified Proof is not generated with this pair-key: %v", proof) + return nil, fmt.Errorf("the specified Proof is not generated with this pair-key: %s", + hex.EncodeToString(proof)) } output, err := vrf.ProofToHash(vrf.Proof(proof)) if err != nil { diff --git a/crypto/ed25519/ed25519_test.go b/crypto/ed25519/ed25519_test.go index 41615d211..b978ee345 100644 --- a/crypto/ed25519/ed25519_test.go +++ b/crypto/ed25519/ed25519_test.go @@ -1,6 +1,8 @@ package ed25519_test import ( + "encoding/hex" + coniks "github.com/coniks-sys/coniks-go/crypto/vrf" "testing" "github.com/stretchr/testify/assert" @@ -28,3 +30,41 @@ func TestSignAndValidateEd25519(t *testing.T) { assert.False(t, pubKey.VerifySignature(msg, sig)) } + +func TestVRFProveAndVRFVerify(t *testing.T) { + + privKey := ed25519.GenPrivKey() + pubKey := privKey.PubKey() + + message, _ := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") + proof, err := privKey.VRFProve(message) + assert.Nil(t, err) + assert.NotNil(t, proof) + + output, err := pubKey.VRFVerify(proof, message) + assert.Nil(t, err) + assert.NotNil(t, output) + + // error + { + message, _ = hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000001") + output, err = pubKey.VRFVerify(proof, message) + assert.NotNil(t, err) + assert.Nil(t, output) + } + + // invalid + { + privateKey, _ := coniks.GenerateKey(nil) + copy(privKey[:], privateKey) + pubKey = privKey.PubKey() + + proof, err = privKey.VRFProve(message) + assert.Nil(t, err) + assert.NotNil(t, proof) + + output, err = pubKey.VRFVerify(proof, message) + assert.NotNil(t, err) + assert.Nil(t, output) + } +} diff --git a/crypto/vrf/README.md b/crypto/vrf/README.md new file mode 100644 index 000000000..b32589b59 --- /dev/null +++ b/crypto/vrf/README.md @@ -0,0 +1,91 @@ +# VRF + +VRF implementation is set by `func init()` with `build` option + +## Interface +* package/file + * line/ostracon/crypto/vrf + * `var defaultVrf vrfEd25519` + * vrf.go + * vrf_test.go +```go +type vrfEd25519 interface { + Prove(privateKey []byte, message []byte) (Proof, error) + Verify(publicKey []byte, proof Proof, message []byte) (bool, error) + ProofToHash(proof Proof) (Output, error) +``` + +## Implementations + +Use `func init()` with `build` option + +* package/file + * line/ostracon/crypto/vrf + * (r2ishiguro = default) + * `// +build !libsodium,!coniks` + * `func init() { defaultVrf = newVrfEd25519r2ishiguro() }` + * vrf_r2ishiguro.go + * (coniks) + * `// +build coniks` + * `func init() { defaultVrf = newVrfEd25519coniks() }` + * vrf_coniks.go + * vrf_coniks_test.go + * (libsodium) + * `// +build libsodium` + * `func init() { defaultVrf = newVrfEd25519libsodium() }` + * vrf_libsodium.go + * vrf_libsodium_test.go + +### Status + +| impl | available | memo | +|:---|:---|:---| +|r2ishiguro|o|(default)| +|coniks|x|no compatibility between *crypto ED25519* and *coniks ED25519* (See `TestProveAndVerify_ConiksByCryptoED25519`)| +|libsodium|o| need to build libsodium (See `libsodium` task of `Makefile`)| + +### Attention + +* There is no compatibility between *r2ishiguro.Prove/libsodium.Verify* and *libsodium.Prove/r2ishiguro.Verify* (See `TestProveAndVerifyCompatibilityLibsodium`) +* Ostracon Network should use `r2ishiguro` or `libsodium` (Can't use both at the same time in Ostracon Network) + +### libsodium (bind C implementations) +* package/file + * line/ostracon/crypto/vrf/internal/vrf + * `// +build libsodium` + * vrf.go + * vrf_test.go + * libsodium: submodule (See `.gitmodule`) + * sodium: libs (See `libsodium` task of `Makefile`) + +## How to test + +```shell +# r2ishiguro +go test github.com/line/ostracon/crypto/vrf -tags r2ishiguro +# libsodium +go test github.com/line/ostracon/crypto/vrf -tags libsodium +# internal libsodium only +go test github.com/line/ostracon/crypto/vrf/internal/vrf -v -tags libsodium + +# coniks is not available, but if you want to do, you can see no-compatibility +go test github.com/line/ostracon/crypto/vrf -tags coniks +``` + +## How to benchmark + +```shell +# r2ishiguro +go test -bench Benchmark github.com/line/ostracon/crypto/vrf -run ^$ -benchtime=1000x -count 10 -benchmem -v +# libsodium +go test -bench Benchmark github.com/line/ostracon/crypto/vrf -run ^$ -benchtime=1000x -count 10 -benchmem -v -tags libsodium +``` + +## How to build + +```shell +# r2ishiguro +make build +# libsodium +LIBSODIUM=1 make build +``` diff --git a/crypto/vrf/internal/vrf/nolibsodium.go b/crypto/vrf/internal/vrf/nolibsodium.go deleted file mode 100644 index 661714066..000000000 --- a/crypto/vrf/internal/vrf/nolibsodium.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build !libsodium - -package vrf - -// currently this constants are not used -// but it is necessary to avoid 'no Go source files' error and -// red compilation error lines in IDE if we don't put libsodium build tag at build command -const ( - PUBLICKEYBYTES = 0 - SECRETKEYBYTES = 0 - SEEDBYTES = 0 - PROOFBYTES = 0 - OUTPUTBYTES = 0 - PRIMITIVE = 0 -) diff --git a/crypto/vrf/internal/vrf/vrf.go b/crypto/vrf/internal/vrf/vrf.go index 84b1a34e7..c8c2083e4 100644 --- a/crypto/vrf/internal/vrf/vrf.go +++ b/crypto/vrf/internal/vrf/vrf.go @@ -5,8 +5,16 @@ package vrf /* #cgo CFLAGS: -Wall -std=c99 -#cgo CFLAGS: -I./include/ -#cgo LDFLAGS: -L./lib -lsodium +#cgo darwin,amd64 CFLAGS: -I./sodium/darwin_amd64/include/ +#cgo darwin,amd64 LDFLAGS: -L./sodium/darwin_amd64/lib -lsodium +#cgo linux,amd64 CFLAGS: -I./sodium/linux_amd64/include +#cgo linux,amd64 LDFLAGS: -L./sodium/linux_amd64/lib -lsodium +#cgo linux,arm64 CFLAGS: -I./sodium/linux_arm64/include +#cgo linux,arm64 LDFLAGS: -L./sodium/linux_arm64/lib -lsodium +#cgo linux,arm CFLAGS: -I./sodium/linux_arm/include +#cgo linux,arm LDFLAGS: -L./sodium/linux_arm/lib -lsodium +#cgo windows,amd64 CFLAGS: -I./sodium/windows_amd64/include +#cgo windows,amd64 LDFLAGS: -L./sodium/windows_amd64/lib -lsodium #include "sodium.h" */ import "C" @@ -14,7 +22,6 @@ import ( "encoding/hex" "errors" "fmt" - "unsafe" ) const ( @@ -26,16 +33,18 @@ const ( PRIMITIVE = C.crypto_vrf_PRIMITIVE ) -var ( - VrfLibsodiumUsed = true -) +func init() { + if C.sodium_init() == -1 { + panic("sodium_init() failed") + } +} // Generate an Ed25519 key pair for use with VRF. func KeyPair() (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { publicKey := [PUBLICKEYBYTES]byte{} privateKey := [SECRETKEYBYTES]byte{} - publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) - privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) + publicKeyPtr := (*C.uchar)(&publicKey[0]) + privateKeyPtr := (*C.uchar)(&privateKey[0]) C.crypto_vrf_keypair(publicKeyPtr, privateKeyPtr) return &publicKey, &privateKey } @@ -44,24 +53,24 @@ func KeyPair() (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { func KeyPairFromSeed(seed *[SEEDBYTES]byte) (*[PUBLICKEYBYTES]byte, *[SECRETKEYBYTES]byte) { publicKey := [PUBLICKEYBYTES]byte{} privateKey := [SECRETKEYBYTES]byte{} - publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) - privateKeyPtr := (*C.uchar)(unsafe.Pointer(&privateKey)) - seedPtr := (*C.uchar)(unsafe.Pointer(seed)) + publicKeyPtr := (*C.uchar)(&publicKey[0]) + privateKeyPtr := (*C.uchar)(&privateKey[0]) + seedPtr := (*C.uchar)(&seed[0]) C.crypto_vrf_keypair_from_seed(publicKeyPtr, privateKeyPtr, seedPtr) return &publicKey, &privateKey } // Verifies that the specified public key is valid. func IsValidKey(publicKey *[PUBLICKEYBYTES]byte) bool { - publicKeyPtr := (*C.uchar)(unsafe.Pointer(publicKey)) + publicKeyPtr := (*C.uchar)(&publicKey[0]) return C.crypto_vrf_is_valid_key(publicKeyPtr) != 0 } // Construct a VRF proof from given secret key and message. func Prove(privateKey *[SECRETKEYBYTES]byte, message []byte) (*[PROOFBYTES]byte, error) { proof := [PROOFBYTES]byte{} - proofPtr := (*C.uchar)(unsafe.Pointer(&proof)) - privateKeyPtr := (*C.uchar)(unsafe.Pointer(privateKey)) + proofPtr := (*C.uchar)(&proof[0]) + privateKeyPtr := (*C.uchar)(&privateKey[0]) messagePtr := bytesToUnsignedCharPointer(message) messageLen := (C.ulonglong)(len(message)) if C.crypto_vrf_prove(proofPtr, privateKeyPtr, messagePtr, messageLen) != 0 { @@ -76,16 +85,17 @@ func Prove(privateKey *[SECRETKEYBYTES]byte, message []byte) (*[PROOFBYTES]byte, // https://tools.ietf.org/html/draft-irtf-cfrg-vrf-04#section-5.3 func Verify(publicKey *[PUBLICKEYBYTES]byte, proof *[PROOFBYTES]byte, message []byte) (*[OUTPUTBYTES]byte, error) { output := [OUTPUTBYTES]byte{} - outputPtr := (*C.uchar)(unsafe.Pointer(&output)) - publicKeyPtr := (*C.uchar)(unsafe.Pointer(publicKey)) - proofPtr := (*C.uchar)(unsafe.Pointer(proof)) + outputPtr := (*C.uchar)(&output[0]) + publicKeyPtr := (*C.uchar)(&publicKey[0]) + proofPtr := (*C.uchar)(&proof[0]) messagePtr := bytesToUnsignedCharPointer(message) messageLen := (C.ulonglong)(len(message)) if C.crypto_vrf_verify(outputPtr, publicKeyPtr, proofPtr, messagePtr, messageLen) != 0 { return nil, errors.New(fmt.Sprintf( "given public key is invalid, or the proof isn't legitimately generated for the message:"+ - " public_key=%s, proof=%s, message=%s", - hex.EncodeToString(publicKey[:]), hex.EncodeToString(proof[:]), hex.EncodeToString(message[:]))) + " public_key=%s, proofSize=%d, proof=%s, message=%s", + hex.EncodeToString(publicKey[:]), len(proof), hex.EncodeToString(proof[:]), + hex.EncodeToString(message[:]))) } return &output, nil } @@ -95,8 +105,8 @@ func Verify(publicKey *[PUBLICKEYBYTES]byte, proof *[PROOFBYTES]byte, message [] // this will return an error. func ProofToHash(proof *[PROOFBYTES]byte) (*[OUTPUTBYTES]byte, error) { output := [OUTPUTBYTES]byte{} - outputPtr := (*C.uchar)(unsafe.Pointer(&output)) - proofPtr := (*C.uchar)(unsafe.Pointer(proof)) + outputPtr := (*C.uchar)(&output[0]) + proofPtr := (*C.uchar)(&proof[0]) if C.crypto_vrf_proof_to_hash(outputPtr, proofPtr) != 0 { return nil, errors.New(fmt.Sprintf( "given proof isn't legitimately generated: proof=%s", hex.EncodeToString(proof[:]))) @@ -106,16 +116,16 @@ func ProofToHash(proof *[PROOFBYTES]byte) (*[OUTPUTBYTES]byte, error) { func SkToPk(privateKey *[SECRETKEYBYTES]byte) *[PUBLICKEYBYTES]byte { publicKey := [PUBLICKEYBYTES]byte{} - publicKeyPtr := (*C.uchar)(unsafe.Pointer(&publicKey)) - privateKeyPtr := (*C.uchar)(unsafe.Pointer(privateKey)) + publicKeyPtr := (*C.uchar)(&publicKey[0]) + privateKeyPtr := (*C.uchar)(&privateKey[0]) C.crypto_vrf_sk_to_pk(publicKeyPtr, privateKeyPtr) // void return &publicKey } func SkToSeed(privateKey *[SECRETKEYBYTES]byte) *[SEEDBYTES]byte { seed := [SEEDBYTES]byte{} - seedPtr := (*C.uchar)(unsafe.Pointer(&seed)) - privateKeyPtr := (*C.uchar)(unsafe.Pointer(privateKey)) + seedPtr := (*C.uchar)(&seed[0]) + privateKeyPtr := (*C.uchar)(&privateKey[0]) C.crypto_vrf_sk_to_seed(seedPtr, privateKeyPtr) // void return &seed } @@ -124,5 +134,5 @@ func bytesToUnsignedCharPointer(msg []byte) *C.uchar { if len(msg) == 0 { return (*C.uchar)(C.NULL) } - return (*C.uchar)(unsafe.Pointer(&msg[0])) + return (*C.uchar)(&msg[0]) } diff --git a/crypto/vrf/internal/vrf/vrf_test.go b/crypto/vrf/internal/vrf/vrf_test.go index 699d150ab..5bf568ada 100644 --- a/crypto/vrf/internal/vrf/vrf_test.go +++ b/crypto/vrf/internal/vrf/vrf_test.go @@ -4,13 +4,9 @@ package vrf import ( "bytes" - "crypto/sha256" "encoding/hex" "math/rand" "testing" - "unsafe" - - "github.com/line/ostracon/crypto/ed25519" ) var ( @@ -95,55 +91,17 @@ func TestKeyPairFromSeed(t *testing.T) { t.Errorf("probe failed: %s", err1) } t.Logf("proof: %s (%d bytes)\n", enc(proof[:]), len(proof)) + if uint32(len(proof)) != PROOFBYTES { + t.Errorf("proof size: %d != %d", len(proof), PROOFBYTES) + } + var output, err2 = ProofToHash(proof) if err2 != nil { t.Errorf("failed to hash proof: %s", err2) } t.Logf("output: %s (%d bytes)\n", enc(output[:]), len(output)) -} - -func TestHashIsDeterministicForKeyPairAndMessage(t *testing.T) { - sk := ed25519.GenPrivKey() - pk, _ := sk.PubKey().(ed25519.PubKeyEd25519) - message := []byte("hello, world") - var hashes = []*Output{} - var proofs = []*Proof{} - for i := 0; i < 100; i++ { - var proof, err1 = prove(&sk, message[:]) - if err1 != nil { - t.Errorf("probe failed: %s", err1) - } else { - hash, err2 := proof.ToHash() - if err2 != nil { - t.Errorf("failed to hash proof: %s", err2) - } else { - output, err3 := verify(&pk, proof, message) - if err3 != nil { - t.Errorf("fail to verify proof: %s", err3) - } else if !bytes.Equal(hash[:], output[:]) { - t.Errorf("hash not match") - } else { - hashes = append(hashes, hash) - proofs = append(proofs, proof) - } - } - } - } - - t.Logf("proofs for \"%s\": %s × %d", string(message), hex.EncodeToString(proofs[0][:]), len(hashes)) - t.Logf("hashes for \"%s\": %s × %d", string(message), hex.EncodeToString(hashes[0][:]), len(hashes)) - - hash := hashes[0] - proof := proofs[0] - for i := 1; i < len(hashes); i++ { - if !bytes.Equal(hash[:], hashes[i][:]) { - t.Errorf("contains different hash: %s != %s", - hex.EncodeToString(hash[:]), hex.EncodeToString(hashes[i][:])) - } - if !bytes.Equal(proof[:], proofs[i][:]) { - t.Errorf("contains different proof: %s != %s", - hex.EncodeToString(proof[:]), hex.EncodeToString(proofs[i][:])) - } + if uint32(len(output)) != OUTPUTBYTES { + t.Errorf("output size: %d != %d", len(output), OUTPUTBYTES) } } @@ -177,20 +135,29 @@ func TestIsValidKey(t *testing.T) { } } -func TestProveAndVerify(t *testing.T) { +func TestInternalProveAndVerify(t *testing.T) { message := []byte("hello, world") var zero [SEEDBYTES]byte var pk, sk = KeyPairFromSeed(&zero) + + t.Logf("private key: [%s]", enc(sk[:])) + t.Logf("public key: [%s]", enc(pk[:])) + var proof, err1 = Prove(sk, message) if err1 != nil { t.Errorf("probe failed: %s", err1) } + + t.Logf("proof: %s", enc(proof[:])) + var output, err2 = ProofToHash(proof) if err2 != nil { t.Errorf("failed to hash proof: %s", err2) } - t.Logf("SEED[%s] -> OUTPUT[%s]\n", enc(zero[:]), enc(output[:])) + + t.Logf("output:[%s] from message:[%s]", enc(output[:]), enc(message)) + var expected, err3 = Verify(pk, proof, message) if err3 != nil { t.Errorf("validation failed: %s", err3) @@ -261,87 +228,3 @@ func TestSkToSeed(t *testing.T) { t.Errorf("seed didn't match: %s != %s", enc(zero[:]), enc(actual[:])) } } - -func TestKeyPairCompatibility(t *testing.T) { - var secret [SEEDBYTES]byte - tmPrivKey := ed25519.GenPrivKeyFromSecret(secret[:]) - tmPubKey, _ := tmPrivKey.PubKey().(ed25519.PubKeyEd25519) - tmPrivKeyBytes := tmPrivKey[:] - tmPubKeyBytes := tmPubKey[:] - - var seed [SEEDBYTES]byte - hashedSecret := sha256.Sum256(secret[:]) - copy(seed[:], hashedSecret[:]) - lsPubKey, lsPrivKey := KeyPairFromSeed(&seed) - - if !bytes.Equal(tmPrivKeyBytes, lsPrivKey[:]) { - t.Errorf("incompatible private key: %s != %s", - enc(tmPrivKeyBytes), enc(lsPrivKey[:])) - } - t.Logf("ostracon: private key: %s (%d bytes)\n", enc(tmPrivKeyBytes[:]), len(tmPrivKey)) - t.Logf("libsodium : private key: %s (%d bytes)\n", enc(lsPrivKey[:]), len(lsPrivKey)) - - if !bytes.Equal(tmPubKeyBytes, lsPubKey[:]) { - t.Errorf("incompatible public key: %s != %s", enc(tmPubKeyBytes), enc(lsPubKey[:])) - } - t.Logf("ostracon: public key: %s (%d bytes)\n", enc(tmPubKeyBytes), len(tmPubKey)) - t.Logf("libsodium : public key: %s (%d bytes)\n", enc(lsPubKey[:]), len(lsPubKey)) - - pubKeyBytesPtr := (*[PUBLICKEYBYTES]byte)(unsafe.Pointer(&tmPubKey)) - if !IsValidKey(pubKeyBytesPtr) { - t.Errorf("ed25519 key is not a valid public key") - } - - // random Tendermint's key-pairs - msg := []byte("hello, world") - for i := 0; i < 100; i++ { - privKey := ed25519.GenPrivKey() - proof, err := prove(&privKey, msg) - if err != nil { - t.Errorf("Prove() failed: %s", err) - } else { - pubKey, _ := privKey.PubKey().(ed25519.PubKeyEd25519) - output, err := verify(&pubKey, proof, msg) - if err != nil { - t.Errorf("Verify() failed: %s", err) - } else { - hash, err := proof.ToHash() - if err != nil { - t.Errorf("Proof.ToHash() failed: %s", err) - } else if !bytes.Equal(hash[:], output[:]) { - t.Errorf("proof hash and verify hash didn't match: %s != %s", - hex.EncodeToString(hash[:]), hex.EncodeToString(output[:])) - } - } - } - } -} - -func TestProve(t *testing.T) { - secret := [SEEDBYTES]byte{} - privateKey := ed25519.GenPrivKeyFromSecret(secret[:]) - publicKey, _ := privateKey.PubKey().(ed25519.PubKeyEd25519) - t.Logf("seed: %s", enc(secret[:])) - t.Logf("private key: [%s]", enc(privateKey[:])) - t.Logf("public key: [%s]", enc(publicKey[:])) - - message := []byte("hello, world") - proof, err1 := prove(&privateKey, message) - if err1 != nil { - t.Fatalf("failed to prove: %s", err1) - } - t.Logf("proof: %s", enc(proof[:])) - - hash1, err2 := proof.ToHash() - if err2 != nil { - t.Fatalf("failed to hash: %s", err2) - } - t.Logf("hash for \"%s\": %s", message, hash1.ToInt()) - - hash2, err3 := verify(&publicKey, proof, message) - if err3 != nil { - t.Errorf("failed to verify: %s", err3) - } else if !bytes.Equal(hash1[:], hash2[:]) { - t.Errorf("incompatible output: %s != %s", enc(hash1[:]), enc(hash2[:])) - } -} diff --git a/crypto/vrf/keygen_test.go b/crypto/vrf/keygen_test.go new file mode 100644 index 000000000..d832b8fd0 --- /dev/null +++ b/crypto/vrf/keygen_test.go @@ -0,0 +1,83 @@ +// +build libsodium + +package vrf + +import ( + "bytes" + "crypto/ed25519" + "github.com/stretchr/testify/require" + "testing" + + coniks "github.com/coniks-sys/coniks-go/crypto/vrf" + libsodium "github.com/line/ostracon/crypto/vrf/internal/vrf" +) + +var secret [SEEDBYTES]byte +var message []byte = []byte("hello, world") + +func keyGen_ed25519(secret [SEEDBYTES]byte) (ed25519.PrivateKey, ed25519.PublicKey) { + privateKey := ed25519.NewKeyFromSeed(secret[:]) + publicKey := privateKey.Public().(ed25519.PublicKey) + return privateKey, publicKey +} + +func keyGen_coniks_ed25519(secret [SEEDBYTES]byte) (ed25519.PrivateKey, ed25519.PublicKey) { + privKey, _ := coniks.GenerateKey(bytes.NewReader(secret[:])) + pubKey, _ := privKey.Public() + privateKey := make([]byte, coniks.PrivateKeySize) + copy(privateKey, privKey[:]) + publicKey := make([]byte, coniks.PublicKeySize) + copy(publicKey, pubKey[:]) + return privateKey, publicKey +} + +func keyGen_libsodium_ed25519(secret [SEEDBYTES]byte) (ed25519.PrivateKey, ed25519.PublicKey) { + pubKey, privKey := libsodium.KeyPairFromSeed(&secret) + privateKey := make([]byte, libsodium.SECRETKEYBYTES) + copy(privateKey, privKey[:]) + publicKey := make([]byte, libsodium.PUBLICKEYBYTES) + copy(publicKey, pubKey[:]) + return privateKey, publicKey +} + +func TestKeyGen(t *testing.T) { + t.Logf("secret: [%s]", enc(secret[:])) + + privateKey, publicKey := keyGen_ed25519(secret) + t.Logf("[ed25519 ]private key: [%s]", enc(privateKey[:])) + t.Logf("[ed25519 ]public key: [%s]", enc(publicKey[:])) + + coniksPrivateKey, coniksPublicKey := keyGen_coniks_ed25519(secret) + t.Logf("[coniks ]private key: [%s]", enc(coniksPrivateKey[:])) + t.Logf("[coniks ]public key: [%s]", enc(coniksPublicKey[:])) + + libsodiumPrivateKey, libsodiumPublicKey := keyGen_libsodium_ed25519(secret) + t.Logf("[libsodium]private key: [%s]", enc(libsodiumPrivateKey[:])) + t.Logf("[libsodium]public key: [%s]", enc(libsodiumPublicKey[:])) + + require.NotEqual(t, privateKey, coniksPrivateKey) + require.NotEqual(t, publicKey, coniksPublicKey) + require.Equal(t, privateKey, libsodiumPrivateKey) + require.Equal(t, publicKey, libsodiumPublicKey) +} + +func BenchmarkKeyGenED25519(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + keyGen_ed25519(secret) + } +} + +func BenchmarkKeyGenConiksED25519(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + keyGen_coniks_ed25519(secret) + } +} + +func BenchmarkKeyGenLibsodiumED25519(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + keyGen_libsodium_ed25519(secret) + } +} diff --git a/crypto/vrf/vrf_coniks.go b/crypto/vrf/vrf_coniks.go index 05e76398b..ce459ed45 100644 --- a/crypto/vrf/vrf_coniks.go +++ b/crypto/vrf/vrf_coniks.go @@ -1,31 +1,36 @@ +// +build coniks + package vrf import ( "bytes" "errors" - coniksimpl "github.com/coniks-sys/coniks-go/crypto/vrf" + coniks "github.com/coniks-sys/coniks-go/crypto/vrf" ) -type vrfEd25519Coniks struct { +type vrfEd25519coniks struct { generatedHash []byte generatedProof []byte } -func newVrfEd25519Coniks() *vrfEd25519Coniks { - return &vrfEd25519Coniks{nil, nil} +func init() { + defaultVrf = newVrfEd25519coniks() +} + +func newVrfEd25519coniks() *vrfEd25519coniks { + return &vrfEd25519coniks{nil, nil} } -//nolint -func newVrfEd25519ConiksForVerifier(output Output, proof Proof) *vrfEd25519Coniks { - return &vrfEd25519Coniks{output, proof} +func newVrfEd25519coniksForVerifier(output Output, proof Proof) *vrfEd25519coniks { + return &vrfEd25519coniks{output, proof} } -func (base *vrfEd25519Coniks) Prove(privateKey []byte, message []byte) (Proof, error) { - if len(privateKey) != coniksimpl.PrivateKeySize { +func (base *vrfEd25519coniks) Prove(privateKey []byte, message []byte) (Proof, error) { + if len(privateKey) != coniks.PrivateKeySize { return nil, errors.New("private key size is invalid") } - coniksPrivKey := coniksimpl.PrivateKey(make([]byte, coniksimpl.PrivateKeySize)) + coniksPrivKey := coniks.PrivateKey(make([]byte, coniks.PrivateKeySize)) copy(coniksPrivKey, privateKey) hash, proof := coniksPrivKey.Prove(message) base.generatedHash = hash @@ -33,22 +38,22 @@ func (base *vrfEd25519Coniks) Prove(privateKey []byte, message []byte) (Proof, e return proof, nil } -func (base *vrfEd25519Coniks) Verify(publicKey []byte, proof Proof, message []byte) (bool, error) { +func (base *vrfEd25519coniks) Verify(publicKey []byte, proof Proof, message []byte) (bool, error) { if base.generatedHash == nil { return false, errors.New("vrf hash was not given") } if !bytes.Equal(base.generatedProof, proof) { return false, errors.New("proof is not same to the previously generated proof") } - if len(publicKey) != coniksimpl.PublicKeySize { + if len(publicKey) != coniks.PublicKeySize { return false, errors.New("public key size is invalid") } - coniksPubKey := coniksimpl.PublicKey(make([]byte, coniksimpl.PublicKeySize)) + coniksPubKey := coniks.PublicKey(make([]byte, coniks.PublicKeySize)) copy(coniksPubKey, publicKey) return coniksPubKey.Verify(message, base.generatedHash, proof), nil } -func (base *vrfEd25519Coniks) ProofToHash(proof Proof) (Output, error) { +func (base *vrfEd25519coniks) ProofToHash(proof Proof) (Output, error) { if base.generatedHash == nil { return nil, errors.New("vrf hash was not given") } diff --git a/crypto/vrf/vrf_coniks_test.go b/crypto/vrf/vrf_coniks_test.go index f0e005011..09a7ce2d6 100644 --- a/crypto/vrf/vrf_coniks_test.go +++ b/crypto/vrf/vrf_coniks_test.go @@ -1,3 +1,5 @@ +// +build coniks + package vrf import ( @@ -6,58 +8,62 @@ import ( "crypto/ed25519" - coniksimpl "github.com/coniks-sys/coniks-go/crypto/vrf" + coniks "github.com/coniks-sys/coniks-go/crypto/vrf" "github.com/stretchr/testify/require" ) -func TestProveAndVerifyConiks(t *testing.T) { +func TestKeyPairCompatibilityConiks(t *testing.T) { secret := [SEEDBYTES]byte{} - privateKey := ed25519.NewKeyFromSeed(secret[:]) - publicKey := privateKey.Public().(ed25519.PublicKey) + privateKey, _ := coniks.GenerateKey(bytes.NewReader(secret[:])) + publicKey, _ := privateKey.Public() - t.Logf("private key: [%s]", enc(privateKey[:])) - t.Logf("public key: [%s]", enc(publicKey[:])) - - vrfImpl := newVrfEd25519Coniks() - message := []byte("hello, world") - proof, err1 := vrfImpl.Prove(privateKey, message) - if err1 != nil { - t.Fatalf("failed to prove: %s", err1) + privateKey2 := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) + copy(privateKey2[:], privateKey[:]) + publicKey2 := privateKey2.Public().(ed25519.PublicKey) + if !bytes.Equal(publicKey, publicKey2[:]) { + t.Error("public key is not matched: using same private key which is generated by coniks", + "coniks.Public", enc(publicKey), "ed25519.Public", enc(publicKey2[:])) } - t.Logf("proof: %s", enc(proof[:])) - hash1, err2 := vrfImpl.ProofToHash(proof) - if err2 != nil { - t.Fatalf("failed to hash: %s", err2) - } - t.Logf("hash for \"%s\": %s", message, hash1.ToInt()) + privateKey2 = ed25519.NewKeyFromSeed(secret[:]) + publicKey2, _ = privateKey2.Public().(ed25519.PublicKey) - verified, err3 := vrfImpl.Verify(publicKey, proof, message) - if err3 != nil { - t.Errorf("failed to verify: %s", err3) + copy(privateKey, privateKey2[:]) + publicKey, _ = privateKey.Public() + if !bytes.Equal(publicKey, publicKey2[:]) { + t.Error("public key is not matched: using same private key which is generated by ed25519", + "coniks.Public", enc(publicKey), "ed25519.Public", enc(publicKey2[:])) } - // coniks seems it cannot digest ed25519 private key - require.False(t, verified) + } -func TestKeyPairCompatibilityConiks(t *testing.T) { +func TestProveAndVerify_ConiksByCryptoED25519(t *testing.T) { secret := [SEEDBYTES]byte{} privateKey := ed25519.NewKeyFromSeed(secret[:]) - publicKey, _ := privateKey.Public().(ed25519.PublicKey) + publicKey := privateKey.Public().(ed25519.PublicKey) - privateKey2 := coniksimpl.PrivateKey(make([]byte, 64)) - copy(privateKey2, privateKey[:]) - publicKey2, _ := privateKey2.Public() - if !bytes.Equal(publicKey[:], publicKey2) { - t.Error("public key is not matched(coniks key -> tm key") + verified, err := proveAndVerify(t, privateKey, publicKey) + if err != nil { + t.Fatalf("failed to verify: %s", err) } + // + // "un-verified" when using crypto ED25519 + // If you want to use coniks, you should use coniks ED25519 + // + require.False(t, verified) +} - privateKey2, _ = coniksimpl.GenerateKey(nil) - publicKey2, _ = privateKey2.Public() +func TestProveAndVerify_ConiksByConiksED25519(t *testing.T) { + secret := [SEEDBYTES]byte{} + privateKey, _ := coniks.GenerateKey(bytes.NewReader(secret[:])) + publicKey, _ := privateKey.Public() - copy(privateKey[:], privateKey2[:]) - publicKey = privateKey.Public().(ed25519.PublicKey) - if !bytes.Equal(publicKey[:], publicKey2) { - t.Error("public key is not matched(tm key -> coniks key") + verified, err := proveAndVerify(t, privateKey, publicKey) + if err != nil { + t.Fatalf("failed to verify: %s", err) } + // + // verified when using coniks ED25519 + // + require.True(t, verified) } diff --git a/crypto/vrf/vrf_libsodium.go b/crypto/vrf/vrf_libsodium.go index 475850dfd..f0a598c58 100644 --- a/crypto/vrf/vrf_libsodium.go +++ b/crypto/vrf/vrf_libsodium.go @@ -6,34 +6,34 @@ package vrf import ( "bytes" - "unsafe" - libsodium "github.com/line/ostracon/crypto/vrf/internal/vrf" ) -type vrfImplLibsodium struct { +type vrfEd25519libsodium struct { } -func newVrfEd25519ImplLibsodium() vrfEd25519 { - return vrfImplLibsodium{} +func init() { + defaultVrf = newVrfEd25519libsodium() } -func init() { - defaultVrf = newVrfEd25519ImplLibsodium() +func newVrfEd25519libsodium() vrfEd25519 { + return vrfEd25519libsodium{} } -func (base vrfImplLibsodium) Prove(privateKey []byte, message []byte) (Proof, error) { - privKey := (*[libsodium.SECRETKEYBYTES]byte)(unsafe.Pointer(&(*privateKey))) - pf, err := libsodium.Prove(privKey, message) +func (base vrfEd25519libsodium) Prove(privateKey []byte, message []byte) (Proof, error) { + var privKey [libsodium.SECRETKEYBYTES]byte + copy(privKey[:], privateKey) + pf, err := libsodium.Prove(&privKey, message) if err != nil { return nil, err } return newProof(pf), nil } -func (base vrfImplLibsodium) Verify(publicKey []byte, proof Proof, message []byte) (bool, error) { - pubKey := (*[libsodium.PUBLICKEYBYTES]byte)(unsafe.Pointer(&publicKey)) - op, err := libsodium.Verify(pubKey, toArray(proof), message) +func (base vrfEd25519libsodium) Verify(publicKey []byte, proof Proof, message []byte) (bool, error) { + var pubKey [libsodium.PUBLICKEYBYTES]byte + copy(pubKey[:], publicKey) + op, err := libsodium.Verify(&pubKey, toArray(proof), message) if err != nil { return false, err } @@ -44,7 +44,7 @@ func (base vrfImplLibsodium) Verify(publicKey []byte, proof Proof, message []byt return bytes.Compare(op[:], hash) == 0, nil } -func (base vrfImplLibsodium) ProofToHash(proof Proof) (Output, error) { +func (base vrfEd25519libsodium) ProofToHash(proof Proof) (Output, error) { op, err := libsodium.ProofToHash(toArray(proof)) if err != nil { return nil, err diff --git a/crypto/vrf/vrf_libsodium_test.go b/crypto/vrf/vrf_libsodium_test.go new file mode 100644 index 000000000..7a488c111 --- /dev/null +++ b/crypto/vrf/vrf_libsodium_test.go @@ -0,0 +1,101 @@ +// +build libsodium + +package vrf + +import ( + "bytes" + "crypto/ed25519" + r2ishiguro "github.com/r2ishiguro/vrf/go/vrf_ed25519" + "github.com/stretchr/testify/require" + "testing" + + coniks "github.com/coniks-sys/coniks-go/crypto/vrf" + libsodium "github.com/line/ostracon/crypto/vrf/internal/vrf" +) + +func TestKeyPairCompatibilityLibsodium(t *testing.T) { + secret := [SEEDBYTES]byte{} + publicKey, privateKey := libsodium.KeyPairFromSeed(&secret) + + privateKey2 := ed25519.PrivateKey(make([]byte, 64)) + copy(privateKey2, privateKey[:]) + publicKey2 := privateKey2.Public().(ed25519.PublicKey) + + if !bytes.Equal(publicKey[:], publicKey2[:]) { + t.Error("public key is not matched: using same private key which is generated by libsodium", + "libsodium.Public", enc(publicKey[:]), "ed25519.Public", enc(publicKey2[:])) + } +} + +func TestProveAndVerify_LibsodiumByCryptoED25519(t *testing.T) { + secret := [SEEDBYTES]byte{} + privateKey := ed25519.NewKeyFromSeed(secret[:]) + publicKey := privateKey.Public().(ed25519.PublicKey) + + verified, err := proveAndVerify(t, privateKey, publicKey) + // + // verified when using crypto ED25519 + // + require.Nil(t, err) + require.True(t, verified) +} + +func TestProveAndVerify_LibsodiumByConiksED25519(t *testing.T) { + secret := [SEEDBYTES]byte{} + privateKey, _ := coniks.GenerateKey(bytes.NewReader(secret[:])) + publicKey, _ := privateKey.Public() + + verified, err := proveAndVerify(t, privateKey, publicKey) + // + // "un-verified" when using coniks ED25519 + // If you want to use libsodium, you should use crypto/libsodium ED25519 + // + require.NotNil(t, err) + require.False(t, verified) +} + +func TestProveAndVerify_LibsodiumByLibsodiumED25519(t *testing.T) { + secret := [SEEDBYTES]byte{} + publicKey, privateKey := libsodium.KeyPairFromSeed(&secret) + + verified, err := proveAndVerify(t, privateKey[:], publicKey[:]) + // + // verified when using libsodium ED25519 + // + require.Nil(t, err) + require.True(t, verified) +} + +func TestProveAndVerifyCompatibilityLibsodium(t *testing.T) { + secret := [SEEDBYTES]byte{} + message := []byte("hello, world") + privateKey := ed25519.NewKeyFromSeed(secret[:]) + publicKey := privateKey.Public().(ed25519.PublicKey) + + libsodiumImpl := newVrfEd25519libsodium() + + { + proof, err := libsodiumImpl.Prove(privateKey, message) + require.Nil(t, err) + require.NotNil(t, proof) + + output, err := r2ishiguro.ECVRF_verify(publicKey, proof, message) + // + // No compatibility between libsodium.Prove and r2ishiguro.Verify + // + require.NotNil(t, err) + require.NotNil(t, output) + } + { + proof, err := r2ishiguro.ECVRF_prove(publicKey, privateKey, message) + require.Nil(t, err) + require.NotNil(t, proof) + + output, err := libsodiumImpl.Verify(publicKey, proof, message) + // + // No compatibility between r2ishiguro.Prove and libsodium.Verify + // + require.NotNil(t, err) + require.NotNil(t, output) + } +} diff --git a/crypto/vrf/vrf_r2ishiguro.go b/crypto/vrf/vrf_r2ishiguro.go index 205cec1b5..7aaa0f58b 100644 --- a/crypto/vrf/vrf_r2ishiguro.go +++ b/crypto/vrf/vrf_r2ishiguro.go @@ -1,4 +1,5 @@ -// +build !libsodium +// default: r2ishiguro +// +build !libsodium,!coniks package vrf diff --git a/crypto/vrf/vrf_test.go b/crypto/vrf/vrf_test.go index 638957ba8..0990f92a4 100644 --- a/crypto/vrf/vrf_test.go +++ b/crypto/vrf/vrf_test.go @@ -32,58 +32,63 @@ func enc(s []byte) string { return hex.EncodeToString(s) } -func TestProofToHash(t *testing.T) { - secret := [SEEDBYTES]byte{} - privateKey := ed25519.NewKeyFromSeed(secret[:]) - message := []byte("hello, world") +func proveAndVerify(t *testing.T, privateKey, publicKey []byte) (bool, error) { + t.Logf("private key: %s (%d bytes)\n", enc(privateKey), len(privateKey)) + t.Logf("public key: %s (%d bytes)\n", enc(privateKey), len(privateKey)) + message := []byte("hello, world") proof, err1 := Prove(privateKey, message) if err1 != nil { t.Fatalf("failed to prove: %s", err1) } + t.Logf("proof: %s (%d bytes)\n", enc(proof[:]), len(proof)) - _, err2 := ProofToHash(proof) + output, err2 := ProofToHash(proof) if err2 != nil { - t.Errorf("failed to convert to hash: %s", enc(proof[:])) + t.Fatalf("failed to hash: %s", err2) } + t.Logf("output: %s (%d bytes)\n", enc(output[:]), len(output)) - t.Skip("Invalid proof checking is available only for libsodium") - // check to fail for invalid proof bytes - for i := range proof { - proof[i] = 0xFF - } - op3, err3 := ProofToHash(proof) - if err3 == nil { - t.Errorf("unexpected hash for invalid proof: %s", enc(op3[:])) - } + return Verify(publicKey, proof, message) } -func TestProve(t *testing.T) { +func TestProveAndVerify(t *testing.T) { secret := [SEEDBYTES]byte{} privateKey := ed25519.NewKeyFromSeed(secret[:]) publicKey := privateKey.Public().(ed25519.PublicKey) - t.Logf("private key: [%s]", enc(privateKey[:])) - t.Logf("public key: [%s]", enc(publicKey[:])) + verified, err := proveAndVerify(t, privateKey, publicKey) - message := []byte("hello, world") - proof, err1 := Prove(privateKey, message) - if err1 != nil { - t.Fatalf("failed to prove: %s", err1) + if err != nil { + t.Fatalf("failed to verify: %s", err) + } else if !verified { + t.Fatalf("incompatible output") } - t.Logf("proof: %s", enc(proof[:])) +} - hash1, err2 := ProofToHash(proof) - if err2 != nil { - t.Fatalf("failed to hash: %s", err2) - } - t.Logf("hash for \"%s\": %s", message, hash1.ToInt()) +func BenchmarkProveAndVerify(b *testing.B) { + secret := [SEEDBYTES]byte{} + privateKey := ed25519.NewKeyFromSeed(secret[:]) + publicKey := privateKey.Public().(ed25519.PublicKey) + message := []byte("hello, world") - verified, err3 := Verify(publicKey, proof, message) - if err3 != nil { - t.Errorf("failed to verify: %s", err3) - } else if !verified { - t.Errorf("incompatible output") + var proof []byte + var err error + b.Run("VRF prove", func(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + proof, err = Prove(privateKey, message) + } + }) + if err != nil { + panic(err) + } + b.Run("VRF verify", func(b *testing.B) { + b.ResetTimer() + _, err = Verify(publicKey, proof, message) + }) + if err != nil { + panic(err) } } diff --git a/state/validation.go b/state/validation.go index 3245347ae..c4915cc65 100644 --- a/state/validation.go +++ b/state/validation.go @@ -176,8 +176,8 @@ func validateBlock(state State, round int32, block *types.Block) error { _, err := val.PubKey.VRFVerify(proof, message) if err != nil { return types.NewErrInvalidProof(fmt.Sprintf( - "verification failed: %s; proof: %v, prevProofHash: %v, height=%d, round=%d, addr: %v", - err.Error(), block.Proof, state.LastProofHash, state.LastBlockHeight, block.Round, block.ProposerAddress)) + "verification failed: %s; proof: %v, height=%d, round=%d, addr: %v", + err.Error(), block.Proof, block.Height, block.Round, block.ProposerAddress)) } return nil diff --git a/test/e2e/Makefile b/test/e2e/Makefile index 9cb7b930c..21491c018 100644 --- a/test/e2e/Makefile +++ b/test/e2e/Makefile @@ -7,12 +7,12 @@ docker: # order to build a binary with an Ostracon node in it (for built-in # ABCI testing). app: - go build -o build/app -tags badgerdb,boltdb,cleveldb,rocksdb ./app + go build -o build/app -tags libsodium,badgerdb,boltdb,cleveldb,rocksdb ./app # To be used primarily by the e2e docker instance. If you want to produce this binary # elsewhere, then run go build in the maverick directory. maverick: - go build -o build/maverick -tags badgerdb,boltdb,cleveldb,rocksdb ../maverick + go build -o build/maverick -tags libsodium,badgerdb,boltdb,cleveldb,rocksdb ../maverick generator: go build -o build/generator ./generator diff --git a/test/e2e/docker/Dockerfile b/test/e2e/docker/Dockerfile index a17e9658c..24b8b30fc 100644 --- a/test/e2e/docker/Dockerfile +++ b/test/e2e/docker/Dockerfile @@ -4,10 +4,11 @@ FROM golang:1.15 RUN apt-get -qq update -y && apt-get -qq upgrade -y >/dev/null -RUN apt-get -qq install -y libleveldb-dev librocksdb-dev >/dev/null +RUN apt-get -qq install -y libleveldb-dev librocksdb-dev libtool >/dev/null # Set up build directory /src/ostracon ENV OSTRACON_BUILD_OPTIONS badgerdb,boltdb,cleveldb,rocksdb +ENV LIBSODIUM 1 WORKDIR /src/ostracon # Fetch dependencies separately (for layer caching) diff --git a/tests.mk b/tests.mk index 224a3874b..bbc4b2d27 100644 --- a/tests.mk +++ b/tests.mk @@ -74,6 +74,11 @@ test_deadlock: @go test -p 1 -v $(PACKAGES) -tags deadlock .PHONY: test_race +test_tags: + @echo "--> Running go test" + @go test -p 1 $(PACKAGES) -tags "$(BUILD_TAGS)" +.PHONY: test + ### # # WARNING: NOT Support Open API 3. See the CONTRIBUTING.md#RPC Testing