Skip to content

Commit

Permalink
Change to use curve25519-voi's VRF (#633)
Browse files Browse the repository at this point in the history
* draft: Use curve25519-voi's vrf function

`make build` passed.
The tendermint/tendermint master uses curve25519 at ed25519.go. Therefore, curve25519-voi should be used from the viewpoint of reducing implementation complexity and cost management. Also, curve25519-voi is based on ed25519-dalek and is more optimized than ref10 in cofactor processing.

* fix: Delete r2ishiguro and libsodium

* refactor: Mark unused parameters

* comment: fix the comment for `VRFVerify`

* fix: Leave the necessary jobs in coverage.yml and delete one unnecessary file

* fix: delete unnecessary line and describe length of proof for curve25519-voi

* typo

* fix: remove an unnecessary line
  • Loading branch information
Kynea0b authored Jun 26, 2023
1 parent 9959bd3 commit 4127ae7
Show file tree
Hide file tree
Showing 41 changed files with 77 additions and 1,509 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,3 @@ jobs:
- name: Build Linux
run: GOOS=linux GOARCH=${{ matrix.goarch }} CC=${{ matrix.gcc }} TARGET_HOST=${{ matrix.host }} make build
if: "env.GIT_DIFF != ''"
- name: Build Linux with Libsodium
run: GOOS=linux GOARCH=${{ matrix.goarch }} CC=${{ matrix.gcc }} TARGET_HOST=${{ matrix.host }} LIBSODIUM=1 make build
if: "env.GIT_DIFF != ''"
21 changes: 2 additions & 19 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,12 @@ jobs:
name: "${{ github.sha }}-05"
path: ./pkgs.txt.part.05

build-libsodium:
name: Build libsodium
runs-on: ubuntu-latest
needs: split-test-files
steps:
- uses: actions/checkout@v3
- run: make libsodium
- uses: actions/upload-artifact@v3
with:
name: libsodium
path: crypto/vrf/internal/vrf/sodium

tests:
runs-on: ubuntu-latest
needs: build-libsodium
needs: split-test-files
strategy:
fail-fast: false
matrix:
vrf: ["r2ishiguro", "libsodium"]
part: ["00", "01", "02", "03", "04", "05"]
steps:
- uses: actions/setup-go@v4
Expand All @@ -74,13 +61,9 @@ jobs:
with:
name: "${{ github.sha }}-${{ matrix.part }}"
if: env.GIT_DIFF
- uses: actions/download-artifact@v3
with:
name: libsodium
path: crypto/vrf/internal/vrf/sodium
- name: test & coverage report creation
run: |
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 7m -race -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags ${{ matrix.vrf }}
cat pkgs.txt.part.${{ matrix.part }} | xargs go test -mod=readonly -timeout 7m -race -coverprofile=${{ matrix.part }}profile.out -covermode=atomic
if: env.GIT_DIFF
- uses: actions/upload-artifact@v3
with:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ jobs:
docker load -i ${{ needs.e2e-build.outputs.CACHE_FILE }}
if: "env.GIT_DIFF != ''"

- name: Build libsodium
run: make libsodium

- name: Build e2e runner
working-directory: test/e2e
run: make runner
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

36 changes: 3 additions & 33 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ OUTPUT?=build/ostracon
INCLUDE = -I=${GOPATH}/src/github.com/Finschia/ostracon -I=${GOPATH}/src -I=${GOPATH}/src/github.com/gogo/protobuf/protobuf
BUILD_TAGS ?= ostracon
VERSION := $(shell git describe --always)
ifeq ($(LIBSODIUM), 1)
BUILD_TAGS += libsodium
LIBSODIUM_TARGET = libsodium
else
BUILD_TAGS += r2ishiguro
LIBSODIUM_TARGET =
endif
LD_FLAGS = -X github.com/Finschia/ostracon/version.OCCoreSemVer=$(VERSION)
BUILD_FLAGS = -mod=readonly -ldflags "$(LD_FLAGS)"
HTTPS_GIT := https://github.com/Finschia/ostracon.git
Expand Down Expand Up @@ -64,11 +57,11 @@ include tests.mk
### Build Ostracon ###
###############################################################################

build: $(LIBSODIUM_TARGET)
build:
CGO_ENABLED=1 go build $(BUILD_FLAGS) -tags "$(BUILD_TAGS)" -o $(OUTPUT) ./cmd/ostracon/
.PHONY: build

install: $(LIBSODIUM_TARGET)
install:
CGO_ENABLED=1 go install $(BUILD_FLAGS) -tags "$(BUILD_TAGS)" ./cmd/ostracon
.PHONY: install

Expand Down Expand Up @@ -138,29 +131,6 @@ install_abci:
### Distribution ###
###############################################################################

########################################
### libsodium

VRF_ROOT = $(SRCPATH)/crypto/vrf/internal/vrf
LIBSODIUM_ROOT = $(VRF_ROOT)/libsodium
LIBSODIUM_OS = $(VRF_ROOT)/sodium/$(TARGET_OS)_$(TARGET_ARCH)
ifneq ($(TARGET_HOST), "")
LIBSODIUM_HOST = "--host=$(TARGET_HOST)"
endif

libsodium:
@if [ ! -f $(LIBSODIUM_OS)/lib/libsodium.a ]; then \
rm -rf $(LIBSODIUM_ROOT) && \
mkdir $(LIBSODIUM_ROOT) && \
git submodule update --init --recursive && \
cd $(LIBSODIUM_ROOT) && \
./autogen.sh && \
./configure --disable-shared --prefix="$(LIBSODIUM_OS)" $(LIBSODIUM_HOST) && \
$(MAKE) && \
$(MAKE) install; \
fi
.PHONY: libsodium

########################################
### Distribution

Expand Down Expand Up @@ -291,7 +261,7 @@ DOCKER_CMD = docker run --rm \
DOCKER_IMG = golang:1.18-alpine
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) \
&& LIBSODIUM=$(LIBSODIUM) make build-linux
&& make build-linux

# Login docker-container for confirmation building linux binary
build-shell:
Expand Down
12 changes: 0 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,6 @@ git clone https://github.com/Finschia/ostracon.git
git clone [email protected]:Finschia/ostracon.git
```

### git clone with recursive if you want to use libsodium
```shell
git clone --recursive https://github.com/Finschia/ostracon.git
# or
git clone --recursive [email protected]:Finschia/ostracon.git
```

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

## Local Standalone
**Build**
```sh
Expand Down
2 changes: 1 addition & 1 deletion crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type PubKey interface {
Address() Address
Bytes() []byte
VerifySignature(msg []byte, sig []byte) bool
VRFVerify(proof Proof, seed []byte) (Output, error) // TODO 🏺 rename to VerifyVRFProof to match VerifySignature
VRFVerify(proof []byte, message []byte) (Output, error)
Equals(PubKey) bool
Type() string
}
Expand Down
34 changes: 13 additions & 21 deletions crypto/ed25519/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import (
"fmt"
"io"

"golang.org/x/crypto/ed25519"

"github.com/Finschia/ostracon/crypto"
"github.com/Finschia/ostracon/crypto/tmhash"
"github.com/Finschia/ostracon/crypto/vrf"
tmjson "github.com/Finschia/ostracon/libs/json"
"github.com/oasisprotocol/curve25519-voi/primitives/ed25519"
vrf "github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/ecvrf"
)

//-------------------------------------
Expand Down Expand Up @@ -63,11 +62,8 @@ func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {

// 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
}
return crypto.Proof(proof[:]), nil
proof := vrf.Prove(ed25519.PrivateKey(privKey[:]), message)
return proof, nil
}

// PubKey gets the corresponding public key from the private key.
Expand Down Expand Up @@ -173,21 +169,17 @@ func (pubKey PubKey) Type() string {
return KeyType
}

// 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: err: %s", err.Error())
}
if !valid {
return nil, fmt.Errorf("the specified Proof is not generated with this pair-key: %s",
// VRFVerify guarantees that the public key is validated such that the "full uniqueness" and
// "full collision" properties are satisfied.
// The internal function of VRFVerify is implemented based on the IETF draft.
// See sections 3.1 and 3.2 here https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/.
func (pubKey PubKey) VRFVerify(proof []byte, message []byte) (crypto.Output, error) {
isValid, hash := vrf.Verify(ed25519.PublicKey(pubKey), proof, message)
if !isValid {
return nil, fmt.Errorf("either Public Key or Proof is an invalid value.: err: %s",
hex.EncodeToString(proof))
}
output, err := vrf.ProofToHash(vrf.Proof(proof))
if err != nil {
return nil, err
}
return crypto.Output(output), nil
return hash, nil
}

func (pubKey PubKey) Equals(other crypto.PubKey) bool {
Expand Down
41 changes: 16 additions & 25 deletions crypto/ed25519/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"encoding/hex"
"testing"

coniks "github.com/coniks-sys/coniks-go/crypto/vrf"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -36,7 +34,6 @@ func TestVRFProveAndVRFVerify(t *testing.T) {

privKey := ed25519.GenPrivKey()
pubKey := privKey.PubKey()

message, _ := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
proof, err := privKey.VRFProve(message)
assert.Nil(t, err)
Expand All @@ -46,26 +43,20 @@ func TestVRFProveAndVRFVerify(t *testing.T) {
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)
}
// *** If the combination of (pubkey, message, proof) is incorrect ***
// invalid message
inValidMessage, _ := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000001")
_, err1 := pubKey.VRFVerify(proof, inValidMessage)
assert.Error(t, err1)

// invalid pubkey
invalidPrivKey := ed25519.GenPrivKey()
invalidPubkey := invalidPrivKey.PubKey()
_, err2 := invalidPubkey.VRFVerify(proof, message)
assert.Error(t, err2)

// invalid proof
invalidProof, _ := invalidPrivKey.VRFProve(message)
_, err3 := pubKey.VRFVerify(invalidProof, message)
assert.Error(t, err3)
}
2 changes: 1 addition & 1 deletion crypto/secp256k1/secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (pubKey PubKey) String() string {
}

// VRFVerify is not supported in Secp256k1.
func (pubKey PubKey) VRFVerify(proof crypto.Proof, seed []byte) (crypto.Output, error) {
func (pubKey PubKey) VRFVerify(_ []byte, _ []byte) (crypto.Output, error) {
return nil, fmt.Errorf("VRF verify is not supported by the secp256k1")
}

Expand Down
2 changes: 1 addition & 1 deletion crypto/sr25519/pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (pubKey PubKey) VerifySignature(msg []byte, sig []byte) bool {
}

// VRFVerify is not supported in Sr25519.
func (pubKey PubKey) VRFVerify(proof crypto.Proof, seed []byte) (crypto.Output, error) {
func (pubKey PubKey) VRFVerify(_ []byte, _ []byte) (crypto.Output, error) {
return nil, fmt.Errorf("VRF verify is not supported by the sr25519")
}

Expand Down
97 changes: 0 additions & 97 deletions crypto/vrf/README.md

This file was deleted.

Loading

0 comments on commit 4127ae7

Please sign in to comment.