add go-dleq; remove all rust dependencies (#242)

This commit is contained in:
noot
2022-11-28 19:31:41 -05:00
committed by GitHub
parent 21c2f2a585
commit 6cdffdbebf
13 changed files with 100 additions and 292 deletions

View File

@@ -41,4 +41,4 @@ jobs:
restore-keys: ${{ runner.os }}-go-mod
- name: Run build
run: make build-go
run: make build

View File

@@ -37,5 +37,4 @@ jobs:
- name: Run go vet
run: |
make init
go vet ./...

4
.gitmodules vendored
View File

@@ -1,4 +0,0 @@
[submodule "dleq/cgo-dleq"]
path = dleq/cgo-dleq
url = https://github.com/athanorlabs/cgo-dleq.git
branch = main

View File

@@ -1,28 +1,19 @@
GOPATH ?= $(shell go env GOPATH)
DLEQ_LIB=dleq/cgo-dleq/lib/libdleq.so
.PHONY: all
all: install
$(DLEQ_LIB):
./scripts/install-rust.sh
git submodule update --init --recursive
cd dleq/cgo-dleq && make build
.PHONY: init
init: $(DLEQ_LIB)
.PHONY: lint-go
lint-go: init
lint-go:
./scripts/install-lint.sh
${GOPATH}/bin/golangci-lint run
.PHONY: lint-shell
lint-shell: init
lint-shell:
shellcheck --source-path=.:scripts scripts/*.sh
.PHONY: lint-solidity
lint-solidity: init
lint-solidity:
"$$(npm config get prefix)/bin/solhint" $$(find ethereum -name '*.sol')
.PHONY: lint
@@ -44,37 +35,32 @@ format-solidity:
format: format-go format-shell format-solidity
.PHONY: test
test: init
test:
./scripts/run-unit-tests.sh 2>&1 | tee test.log
.PHONY: test-integration
test-integration: init
test-integration:
./scripts/run-integration-tests.sh 2>&1 | tee test-integration.log
# Install all the binaries into $HOME/go/bin (or alternative GOPATH bin directory)
.PHONY: install
install: init
install:
go install ./cmd/...
# Install swapd and swapcli into this directory (top of the project)
.PHONY: build
build: init
build:
./scripts/build.sh
# WARNING: this should not be used in production, as the DLEq prover has been stubbed out and now proves nothing.
.PHONY: build-go
build-go:
GOBIN="$(CURDIR)/bin" go build -tags=fakedleq ./cmd/swapd
GOBIN="$(CURDIR)/bin" go build -tags=fakedleq ./cmd/swapcli
# WARNING: this should not be used in production, as the DLEq prover has been stubbed out and now proves nothing.
.PHONY: build-go-darwin
build-go-darwin:
GOOS=darwin GOARCH=arm64 $(MAKE) build-go
# Test macos/arm build from linux. Use "make build" if compiling on macos.
.PHONY: build-darwin
build-darwin:
mkdir -p bin/
GOOS=darwin GOARCH=arm64 go build -o ./bin ./cmd/...
# Same as build, but also includes some lesser used binaries
.PHONY: build-all
build-all: init
build-all:
ALL=true $(MAKE) build
# Go bindings for solidity contracts
@@ -89,10 +75,7 @@ mock:
go generate -run mockgen ./...
# Deletes all executables matching the directory names in cmd/
.PHONY: clean-go
clean-go:
rm -f bin/
.PHONY: clean
clean: clean-go
rm -f $(DLEQ_LIB)
clean:
rm -r bin/

Submodule dleq/cgo-dleq deleted from ca62cc9baa

View File

@@ -1,55 +0,0 @@
//go:build !fakedleq
package dleq
import (
"errors"
dleq "github.com/athanorlabs/cgo-dleq"
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/athanorlabs/atomic-swap/crypto/secp256k1"
)
// DefaultDLEq is CGODLEq
type DefaultDLEq = CGODLEq
// CGODLEq is a wrapper around the CGO bindings to dleq-rs
type CGODLEq struct{}
// Prove generates a new DLEq proof
func (d *CGODLEq) Prove() (*Proof, error) {
proof, pk, err := dleq.Ed25519Secp256k1Prove()
if err != nil {
return nil, err
}
var secret [32]byte
copy(secret[:], pk)
return &Proof{
secret: secret,
proof: []byte(proof),
}, nil
}
// Verify verifies a DLEq proof
func (d *CGODLEq) Verify(proof *Proof) (*VerifyResult, error) {
ed25519Pub, secp256k1Pub, err := dleq.Ed25519Secp256k1Verify(proof.proof)
if err != nil {
return nil, err
}
var edPub [32]byte
copy(edPub[:], []byte(ed25519Pub))
x, y := ethsecp256k1.DecompressPubkey([]byte(secp256k1Pub))
if x == nil {
return nil, errors.New("failed to decompress secp256k1 public key")
}
return &VerifyResult{
ed25519Pub: edPub,
secp256k1Pub: secp256k1.NewPublicKeyFromBigInt(x, y),
}, nil
}

View File

@@ -1,82 +0,0 @@
//go:build !fakedleq
package dleq
import (
"bytes"
"crypto/ecdsa"
"math/big"
"testing"
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/athanorlabs/atomic-swap/common"
mcrypto "github.com/athanorlabs/atomic-swap/crypto/monero"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
func TestCGODLEq(t *testing.T) {
proof, err := (&CGODLEq{}).Prove()
require.NoError(t, err)
res, err := (&CGODLEq{}).Verify(proof)
require.NoError(t, err)
cpk := res.secp256k1Pub.Compress()
_, err = ethcrypto.DecompressPubkey(cpk[:])
require.NoError(t, err)
sk, err := mcrypto.NewPrivateSpendKey(proof.secret[:])
require.NoError(t, err)
ed25519Pub := sk.Public().Bytes()
require.Equal(t, res.ed25519Pub[:], ed25519Pub)
}
func TestCGODLEq_Invalid(t *testing.T) {
proof, err := (&CGODLEq{}).Prove()
require.NoError(t, err)
proof.proof[0] = 0
_, err = (&CGODLEq{}).Verify(proof)
require.Error(t, err)
}
func TestProofSecretComputesVerifyPubKeys(t *testing.T) {
// It would be nice to increase the number of iterations, but it's pretty slow even at 128. We
// previously had an issue when X or Y needed at least one high order padding byte. The chance
// of that happening is around (1/256+1/256)=1/128, so this loop will see values like that
// frequently, even if it doesn't happen on every run.
const iterations = 128
toBigInt := func(point [32]byte) *big.Int { return new(big.Int).SetBytes(point[:]) }
for i := 0; i < iterations; i++ {
proof, err := (&CGODLEq{}).Prove()
require.NoError(t, err)
res, err := (&CGODLEq{}).Verify(proof)
require.NoError(t, err)
// The ETH library needs the secret in big-endian format, while the monero library wants it
// in little endian format.
secretBE := proof.secret[:]
secretLE := common.Reverse(secretBE)
// Secp256k1 check
ethCurve := ethsecp256k1.S256()
xPub, yPub := ethCurve.ScalarBaseMult(secretLE)
ethPubFromSecret := &ecdsa.PublicKey{Curve: ethCurve, X: xPub, Y: yPub}
ethPubFromVerify := &ecdsa.PublicKey{Curve: ethCurve,
X: toBigInt(res.Secp256k1PublicKey().X()), Y: toBigInt(res.Secp256k1PublicKey().Y()),
}
require.True(t, ethPubFromSecret.Equal(ethPubFromVerify))
// ED25519 Check
sk, err := mcrypto.NewPrivateSpendKey(secretBE)
require.NoError(t, err)
xmrPubFromSecret := sk.Public().Bytes()
xmrPubFromVerify := res.ed25519Pub[:]
require.True(t, bytes.Equal(xmrPubFromSecret, xmrPubFromVerify))
}
}

View File

@@ -1,101 +0,0 @@
//go:build fakedleq
package dleq
import (
"crypto/rand"
"fmt"
"github.com/athanorlabs/atomic-swap/common"
"github.com/athanorlabs/atomic-swap/crypto/secp256k1"
ed25519 "filippo.io/edwards25519"
dsecp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// DefaultDLEq is FakeDLEq
type DefaultDLEq = FakeDLEq
// FakeDLEq generates a secret scalar that has a point on both curves,
// but doesn't actually prove it.
type FakeDLEq struct{}
// Prove returns a *Proof with a secret key, but no proof.
func (d *FakeDLEq) Prove() (*Proof, error) {
const (
ed25519BitSize = 252
secp256k1BitSize = 255
)
bits := min(ed25519BitSize, secp256k1BitSize)
// generate secret
s, err := generateRandomBits(bits)
if err != nil {
return nil, err
}
var secret [32]byte
copy(secret[:], s)
// generate secp256k1 public key
curve := dsecp256k1.S256()
// ScalarBaseMult param is BE
x, y := curve.ScalarBaseMult(common.Reverse(s))
secp256k1Pub := secp256k1.NewPublicKeyFromBigInt(x, y)
// generate ed25519 public key
ed25519Sk, err := ed25519.NewScalar().SetCanonicalBytes(s)
if err != nil {
return nil, fmt.Errorf("failed to convert secret to ed25519 pubkey: %w", err)
}
ed25519Pk := ed25519.NewIdentityPoint().ScalarBaseMult(ed25519Sk)
var ed25519Pub [32]byte
copy(ed25519Pub[:], ed25519Pk.Bytes())
return &Proof{
secret: secret,
// embed the public keys as the "proof" for when the counterparty "verifies"
proof: append(secp256k1Pub.Bytes(), ed25519Pub[:]...),
}, nil
}
// Verify returns the public keys corresponding to the secret key.
// It only fails if it's unable to generate the public keys.
func (d *FakeDLEq) Verify(proof *Proof) (*VerifyResult, error) {
// generate secp256k1 public key
secp256k1Pub, err := secp256k1.NewPublicKeyFromBytes(proof.proof[:64])
if err != nil {
return nil, err
}
var ed25519Pub [32]byte
copy(ed25519Pub[:], proof.proof[64:96])
return &VerifyResult{
secp256k1Pub: secp256k1Pub,
ed25519Pub: ed25519Pub,
}, nil
}
func min(a, b uint64) uint64 {
if a < b {
return a
}
return b
}
// generateRandomBits generates up to 256 random bits.
func generateRandomBits(bits uint64) ([]byte, error) {
x := make([]byte, 32)
_, err := rand.Read(x)
if err != nil {
return nil, err
}
toClear := 256 - bits
x[31] &= 0xff >> toClear
return x, nil
}

77
dleq/go_dleq.go Normal file
View File

@@ -0,0 +1,77 @@
package dleq
import (
csecp256k1 "github.com/athanorlabs/atomic-swap/crypto/secp256k1"
dleq "github.com/athanorlabs/go-dleq"
"github.com/athanorlabs/go-dleq/ed25519"
"github.com/athanorlabs/go-dleq/secp256k1"
dsecp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
// DefaultDLEq is the default DLEq prover.
// Currently, the only implementation is GoDLEq.
type DefaultDLEq = GoDLEq
// GoDLEq is a wrapper around the go-dleq library prover and verifier.
type GoDLEq struct{}
var (
curveEthereum = secp256k1.NewCurve()
curveMonero = ed25519.NewCurve()
)
// Prove generates a secret scalar and a proof that it has a corresponding
// public key on the secp256k1 and ed25519 curves.
func (d *GoDLEq) Prove() (*Proof, error) {
x, err := dleq.GenerateSecretForCurves(curveEthereum, curveMonero)
if err != nil {
return nil, err
}
proof, err := dleq.NewProof(curveEthereum, curveMonero, x)
if err != nil {
return nil, err
}
err = proof.Verify(curveEthereum, curveMonero)
if err != nil {
return nil, err
}
return &Proof{
proof: proof.Serialize(),
secret: x,
}, nil
}
// Verify verifies the given proof. It returns the secp256k1
// and ed25519 public keys corresponding to the secret value.
func (d *GoDLEq) Verify(p *Proof) (*VerifyResult, error) {
dleqProof := new(dleq.Proof)
err := dleqProof.Deserialize(curveEthereum, curveMonero, p.proof)
if err != nil {
return nil, err
}
err = dleqProof.Verify(curveEthereum, curveMonero)
if err != nil {
return nil, err
}
secpPub, err := dsecp256k1.ParsePubKey(dleqProof.CommitmentA.Encode())
if err != nil {
return nil, err
}
secp256k1Pub := csecp256k1.NewPublicKeyFromBigInt(secpPub.X(), secpPub.Y())
var ed25519Pub [32]byte
copy(ed25519Pub[:], dleqProof.CommitmentB.Encode())
return &VerifyResult{
secp256k1Pub: secp256k1Pub,
ed25519Pub: ed25519Pub,
}, nil
}

View File

@@ -1,5 +1,3 @@
//go:build fakedleq
package dleq
import (
@@ -11,11 +9,11 @@ import (
"github.com/stretchr/testify/require"
)
func TestFakeDLEq(t *testing.T) {
proof, err := (&FakeDLEq{}).Prove()
func TestGoDLEq(t *testing.T) {
proof, err := (&GoDLEq{}).Prove()
require.NoError(t, err)
res, err := (&FakeDLEq{}).Verify(proof)
res, err := (&GoDLEq{}).Verify(proof)
require.NoError(t, err)
cpk := res.secp256k1Pub.Compress()

4
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/ChainSafe/chaindb v0.1.5-0.20221010190531-f900218c88f8
github.com/MarinX/monerorpc v1.0.5
github.com/Masterminds/semver/v3 v3.1.1
github.com/athanorlabs/cgo-dleq v0.0.0-20220929204103-ca62cc9baa28
github.com/athanorlabs/go-dleq v0.0.0-20221128222932-a32f415aaa2d
github.com/athanorlabs/go-relayer v0.0.4
github.com/athanorlabs/go-relayer-client v0.0.0-20221103041240-2aad2e8fc742
github.com/btcsuite/btcd/btcutil v1.1.2
@@ -161,5 +161,3 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
replace github.com/athanorlabs/cgo-dleq => ./dleq/cgo-dleq

2
go.sum
View File

@@ -65,6 +65,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/athanorlabs/go-dleq v0.0.0-20221128222932-a32f415aaa2d h1:KP3F8Rn4N84Vi5+PSxldaSj5T+/nssxICixF1xcJD4g=
github.com/athanorlabs/go-dleq v0.0.0-20221128222932-a32f415aaa2d/go.mod h1:DWry6jSD7A13MKmeZA0AX3/xBeQCXDoygX99VPwL3yU=
github.com/athanorlabs/go-relayer v0.0.4 h1:KcibOFqXZJ6D/BzYAUpvtlG2LNu5NiN1MaCLxVWb4Z4=
github.com/athanorlabs/go-relayer v0.0.4/go.mod h1:7zbS8EWdZaMqfvi/mMxN+f0gqczwBHeOWhEu80d6/Uk=
github.com/athanorlabs/go-relayer-client v0.0.0-20221103041240-2aad2e8fc742 h1:8XIlVAZ5K40kQw8qpQW6fb9rbYr4yzyajhHkMw9rMV0=

View File

@@ -1,6 +0,0 @@
#!/bin/bash
if ! command -v rustup &>/dev/null; then
curl https://sh.rustup.rs -sSf | sh
fi
rustup default stable
rustup update