mirror of
https://github.com/AthanorLabs/atomic-swap.git
synced 2026-01-09 14:18:03 -05:00
add go-dleq; remove all rust dependencies (#242)
This commit is contained in:
2
.github/workflows/build-macos.yaml
vendored
2
.github/workflows/build-macos.yaml
vendored
@@ -41,4 +41,4 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-go-mod
|
||||
|
||||
- name: Run build
|
||||
run: make build-go
|
||||
run: make build
|
||||
|
||||
1
.github/workflows/checks.yml
vendored
1
.github/workflows/checks.yml
vendored
@@ -37,5 +37,4 @@ jobs:
|
||||
|
||||
- name: Run go vet
|
||||
run: |
|
||||
make init
|
||||
go vet ./...
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -1,4 +0,0 @@
|
||||
[submodule "dleq/cgo-dleq"]
|
||||
path = dleq/cgo-dleq
|
||||
url = https://github.com/athanorlabs/cgo-dleq.git
|
||||
branch = main
|
||||
49
Makefile
49
Makefile
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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
77
dleq/go_dleq.go
Normal 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
|
||||
}
|
||||
@@ -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
4
go.mod
@@ -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
2
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user