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

Update libsodium impl and add benchmark test #303

Merged
merged 1 commit into from
Aug 18, 2021
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
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is node.js required to build libsodium?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no relation node.js. This is a just temporary data directory on the test.

crypto/vrf/internal/vrf/sodium
40 changes: 20 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 [email protected]: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 [email protected]:line/ostracon.git
```

### git submodule if you forget to clone with submodule
```shell
git submodule update --init --recursive
```

## Local Standalone
**Build**
```sh
Expand Down
6 changes: 3 additions & 3 deletions crypto/composite/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 10 additions & 8 deletions crypto/ed25519/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ed25519
import (
"bytes"
"crypto/subtle"
"encoding/hex"
"fmt"
"io"

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions crypto/ed25519/ed25519_test.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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)
}
}
91 changes: 91 additions & 0 deletions crypto/vrf/README.md
Original file line number Diff line number Diff line change
@@ -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
```
15 changes: 0 additions & 15 deletions crypto/vrf/internal/vrf/nolibsodium.go

This file was deleted.

Loading