Skip to content

Commit 11ff272

Browse files
CassOnMarsagostbirodemipoet
authored
v1.4.17 – Aurora (#169)
* v1.4.17 – Aurora * binaries, digests, and first signature * signer #3 verified * signer #8 verified * signer #14 verified * signer #12 verified * Add signatures (#170) * Add files via upload (#171) * signer #4 verified * signer #11 verified * signer #16 verified * signer #1 verified * remove binaries from repo, release ready --------- Co-authored-by: Agost Biro <5764438+agostbiro@users.noreply.github.com> Co-authored-by: Demipoet <161999657+demipoet@users.noreply.github.com>
1 parent 6068cd8 commit 11ff272

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+467
-14
lines changed

client/cmd/crossMint.go

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package cmd
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/hex"
6+
"encoding/json"
7+
"fmt"
8+
"os"
9+
"path/filepath"
10+
"strings"
11+
12+
"github.com/cloudflare/circl/sign/ed448"
13+
libP2pCrypto "github.com/libp2p/go-libp2p/core/crypto"
14+
"github.com/pkg/errors"
15+
"github.com/spf13/cobra"
16+
"go.uber.org/zap"
17+
"source.quilibrium.com/quilibrium/monorepo/node/config"
18+
"source.quilibrium.com/quilibrium/monorepo/node/keys"
19+
)
20+
21+
var crossMintCmd = &cobra.Command{
22+
Use: "cross-mint",
23+
Short: "Signs a payload from the Quilibrium bridge to mint tokens on Ethereum L1 and prints the result to stdout",
24+
Long: `Signs a payload from the Quilibrium bridge to mint tokens on Ethereum L1 and prints the result to stdout":
25+
26+
cross-mint <Payload>
27+
28+
Payload – the hex-encoded payload from the Quilibrium bridge with optional 0x-prefix, must be specified
29+
`,
30+
Run: func(cmd *cobra.Command, args []string) {
31+
if len(args) != 1 {
32+
fmt.Printf("missing payload")
33+
os.Exit(1)
34+
}
35+
36+
_, err := os.Stat(configDirectory)
37+
if os.IsNotExist(err) {
38+
fmt.Printf("config directory doesn't exist: %s", configDirectory)
39+
os.Exit(1)
40+
}
41+
42+
config, err := config.LoadConfig(configDirectory, "")
43+
if err != nil {
44+
fmt.Printf("invalid config directory: %s", configDirectory)
45+
os.Exit(1)
46+
}
47+
48+
rawPeerKey, err := hex.DecodeString(config.P2P.PeerPrivKey)
49+
if err != nil {
50+
panic(errors.Wrap(err, "cross mint"))
51+
}
52+
53+
peerKey, err := libP2pCrypto.UnmarshalEd448PrivateKey(rawPeerKey)
54+
if err != nil {
55+
panic(errors.Wrap(err, "cross mint"))
56+
}
57+
58+
rawPeerKey, err = peerKey.Raw()
59+
if err != nil {
60+
panic(errors.Wrap(err, "cross mint"))
61+
}
62+
63+
// TODO: support other key managers
64+
// Get the proving key
65+
// `config.Key.KeyStoreFile.Path` defaults to `.config/keys.yml`.
66+
// We do our best here to make sure the configuration value is taken into
67+
// account if it was changed.
68+
if !filepath.IsAbs(config.Key.KeyStoreFile.Path) {
69+
config.Key.KeyStoreFile.Path = filepath.Join(
70+
configDirectory,
71+
filepath.Base(config.Key.KeyStoreFile.Path),
72+
)
73+
}
74+
75+
logger, err := zap.NewProduction()
76+
if err != nil {
77+
panic(errors.Wrap(err, "cross mint"))
78+
}
79+
80+
fileKeyManager := keys.NewFileKeyManager(config.Key, logger)
81+
provingKey, err := fileKeyManager.GetSigningKey(config.Engine.ProvingKeyId)
82+
if err != nil {
83+
panic(errors.Wrap(err, "cross mint"))
84+
}
85+
// Sign the payload
86+
result, err := CrossMint(&CrossMintArgs{
87+
Payload: args[0],
88+
PeerKey: rawPeerKey,
89+
ProvingKey: provingKey.(ed448.PrivateKey),
90+
})
91+
if err != nil {
92+
panic(errors.Wrap(err, "error cross minting"))
93+
}
94+
// Print the result
95+
jsonResult, err := json.Marshal(result)
96+
if err != nil {
97+
panic(errors.Wrap(err, "error marshaling result to json"))
98+
}
99+
fmt.Println(string(jsonResult))
100+
},
101+
}
102+
103+
func init() {
104+
rootCmd.AddCommand(crossMintCmd)
105+
}
106+
107+
// CrossMintArgs Arguments for the cross mint operation
108+
type CrossMintArgs struct {
109+
// Hex encoded payload with optional 0x prefix
110+
Payload string
111+
// The node's ed448 peer key
112+
PeerKey ed448.PrivateKey
113+
// The node's ed448 proving key
114+
ProvingKey ed448.PrivateKey
115+
}
116+
117+
// CrossMintResult Result of the cross mint operation
118+
type CrossMintResult struct {
119+
// Base64 encoded peer public key
120+
PeerPublicKey string `json:"peerPublicKey"`
121+
// Base64 encoded signature of the payload with the peer private key
122+
PeerSignature string `json:"peerSignature"`
123+
// Base64 encoded prover public key
124+
ProverPublicKey string `json:"proverPublicKey"`
125+
// Base64 encoded signature of the payload with the prover private key
126+
ProverSignature string `json:"proverSignature"`
127+
}
128+
129+
func CrossMint(args *CrossMintArgs) (*CrossMintResult, error) {
130+
rawPayload, err := decodeHexString(args.Payload)
131+
if err != nil {
132+
return nil, errors.Wrap(err, "cross mint")
133+
}
134+
135+
peerSignature := ed448.Sign(args.PeerKey, rawPayload, "")
136+
peerPubKey, ok := args.PeerKey.Public().(ed448.PublicKey)
137+
if !ok {
138+
return nil, errors.Wrap(
139+
errors.New("error casting peer public key to ed448 public key"),
140+
"cross mint",
141+
)
142+
}
143+
144+
provingSignature := ed448.Sign(
145+
args.ProvingKey,
146+
rawPayload,
147+
"",
148+
)
149+
provingPubKey, ok := args.ProvingKey.Public().(ed448.PublicKey)
150+
if !ok {
151+
return nil, errors.Wrap(
152+
errors.New("error casting proving public key to ed448 public key"),
153+
"cross mint",
154+
)
155+
}
156+
return &CrossMintResult{
157+
PeerPublicKey: base64.StdEncoding.EncodeToString(peerPubKey),
158+
PeerSignature: base64.StdEncoding.EncodeToString(peerSignature),
159+
ProverPublicKey: base64.StdEncoding.EncodeToString(provingPubKey),
160+
ProverSignature: base64.StdEncoding.EncodeToString(provingSignature),
161+
}, nil
162+
}
163+
164+
// VerifyCrossMint Verify a cross-mint message. Returns true if both signatures
165+
// verify with the given public keys.
166+
func VerifyCrossMint(payload string, result *CrossMintResult) (bool, error) {
167+
payloadBytes, err := decodeHexString(payload)
168+
if err != nil {
169+
return false, err
170+
}
171+
peerPubKeyBytes, err := base64.StdEncoding.DecodeString(result.PeerPublicKey)
172+
if err != nil {
173+
return false, err
174+
}
175+
peerPubKey := ed448.PublicKey(peerPubKeyBytes)
176+
peerSignature, err := base64.StdEncoding.DecodeString(result.PeerSignature)
177+
if err != nil {
178+
return false, err
179+
}
180+
proverPubKeyBytes, err := base64.StdEncoding.DecodeString(
181+
result.ProverPublicKey,
182+
)
183+
if err != nil {
184+
return false, err
185+
}
186+
proverPubKey := ed448.PublicKey(proverPubKeyBytes)
187+
proverSignature, err := base64.StdEncoding.DecodeString(
188+
result.ProverSignature,
189+
)
190+
if err != nil {
191+
return false, err
192+
}
193+
peerSigOk := ed448.Verify(peerPubKey, payloadBytes, peerSignature, "")
194+
proverSigOk := ed448.Verify(proverPubKey, payloadBytes, proverSignature, "")
195+
return peerSigOk && proverSigOk, nil
196+
}
197+
198+
func decodeHexString(hexStr string) ([]byte, error) {
199+
// Check if the string starts with '0x' and remove it
200+
if strings.HasPrefix(hexStr, "0x") {
201+
hexStr = hexStr[2:]
202+
}
203+
// Decode the hex string into bytes
204+
data, err := hex.DecodeString(hexStr)
205+
if err != nil {
206+
return nil, errors.Wrap(err, "error decoding hex string")
207+
}
208+
return data, nil
209+
}

client/cmd/crossMint_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cmd_test
2+
3+
import (
4+
"crypto/rand"
5+
"encoding/hex"
6+
"encoding/json"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"source.quilibrium.com/quilibrium/monorepo/client/cmd"
11+
)
12+
13+
var peerPrivKeyStr = "b14b843edf61a58870d3f96fe7dc8c6d0479af10aa16c45b102ddae75b278e8ef302edca36c71c1b4beb60e88088826c4da71ab0b5bf60cc92fc35078fa499f8a4accd51776ecc1fb520fdb20408133366077dadf4ff8a337fb42a19ff846e3609516a3f61c92ea4b9c2298a64b8bfae3780"
14+
var provingPrivKeyStr = "690a5f08a2b3a0b787a8301c5fded376f7a070f5d89f66bf537d67fa1ed71a2b22ce166733b7d73ccf10a20ef0f04f163aae13883ff8270f93fed723c513e24e7f93d317b3257731887411bf820e169a0180c0cbf625efa67ff54cc22f1d97a2bd3f721705eeb4c2bf022f793954a798f700"
15+
16+
func TestCrossMintRoundtrip(t *testing.T) {
17+
peerPrivKey, err := hex.DecodeString(peerPrivKeyStr)
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
provingPrivKey, err := hex.DecodeString(provingPrivKeyStr)
22+
if err != nil {
23+
t.Fatal(err)
24+
}
25+
payloadBytes := make([]byte, 32)
26+
n, err := rand.Read(payloadBytes)
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
if n != 32 {
31+
t.Fatal("not enough bytes read")
32+
}
33+
payload := hex.EncodeToString(payloadBytes)
34+
args := &cmd.CrossMintArgs{
35+
Payload: payload,
36+
PeerKey: peerPrivKey,
37+
ProvingKey: provingPrivKey,
38+
}
39+
result, err := cmd.CrossMint(args)
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
verified, err := cmd.VerifyCrossMint(payload, result)
44+
assert.True(t, verified, "cross mint verification failed")
45+
// Switch the public keys to induce failure
46+
tmp := result.PeerPublicKey
47+
result.PeerPublicKey = result.ProverPublicKey
48+
result.ProverPublicKey = tmp
49+
verified, err = cmd.VerifyCrossMint(payload, result)
50+
assert.False(t, verified, "cross mint verification should have failed")
51+
}
52+
53+
func TestCrossMint0xHex(t *testing.T) {
54+
peerPrivKey, err := hex.DecodeString(peerPrivKeyStr)
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
provingPrivKey, err := hex.DecodeString(provingPrivKeyStr)
59+
if err != nil {
60+
t.Fatal(err)
61+
}
62+
63+
payload := "0x1234"
64+
args := &cmd.CrossMintArgs{
65+
Payload: payload,
66+
PeerKey: peerPrivKey,
67+
ProvingKey: provingPrivKey,
68+
}
69+
result, err := cmd.CrossMint(args)
70+
if err != nil {
71+
t.Fatal(err)
72+
}
73+
verified, err := cmd.VerifyCrossMint(payload, result)
74+
assert.True(t, verified, "cross mint verification failed")
75+
}
76+
77+
func TestCrossMintFixture(t *testing.T) {
78+
// Generated by running the `cross-mint` on the config of a newly started node with payload "1234"
79+
rawJson := `{
80+
"peerPublicKey": "LLP/9tYlqIsV8AgTkyIpK9zjN+OfXNmYMDhmDeEagCMAhjfpPPWDyWDq9w6uMl9hGyDKYB10EV0A",
81+
"peerSignature": "2ybumA9Vu5rnr5nYPcjehGo/PK6uNl4iVa0WXkEGms5ChqPFgOJX6Z5eng8U6VSHy85zbeZBukiANE3j2EBxrk4TAf4Z+5uuNMCQ6DasKpkgsxuIOGWKhOcBal2CDicinuMqafU3YOrXH9cck/OkjywA",
82+
"proverPublicKey": "CAk3inpisW2Bpcar/z5/3dwjRSgFMRbhYhtCWdQThZZqDvOWFGgoMXLyKHw3B4+yEsmYIVaQZ/iA",
83+
"proverSignature": "NZb7D2xNbCLlYGMUN1BiwBJL9Z6LbdRiMT1FpltBVpRNuoUNmncN++TWgJD6ngIv+VxEnWB0fhcAfAvrIlwNL0z8Ppur8mGMwedzJIm3pB22nAjUTDvNOvvczZWNbPZPyXcWco8SIC/aVaNmvsg//SgA"
84+
}`
85+
// load RawJson into a CrossMintResult
86+
result := &cmd.CrossMintResult{}
87+
err := json.Unmarshal([]byte(rawJson), result)
88+
if err != nil {
89+
t.Fatal(err)
90+
}
91+
ok, err := cmd.VerifyCrossMint("1234", result)
92+
if err != nil {
93+
t.Fatal(err)
94+
}
95+
assert.True(t, ok, "cross mint verification failed")
96+
97+
bad, err := cmd.VerifyCrossMint("2234", result)
98+
if err != nil {
99+
t.Fatal(err)
100+
}
101+
assert.False(t, bad, "cross mint verification succeeded when it should have failed")
102+
}

client/go.mod

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,41 @@ module source.quilibrium.com/quilibrium/monorepo/client
22

33
go 1.20
44

5+
replace github.com/libp2p/go-libp2p => ../go-libp2p
6+
7+
replace source.quilibrium.com/quilibrium/monorepo/node => ../node
8+
9+
replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
10+
11+
require github.com/stretchr/testify v1.8.4
12+
13+
require (
14+
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
15+
github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401 // indirect
16+
github.com/bwesterb/go-ristretto v1.2.3 // indirect
17+
github.com/consensys/gnark-crypto v0.5.3 // indirect
18+
github.com/davecgh/go-spew v1.1.1 // indirect
19+
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
20+
github.com/minio/sha256-simd v1.0.1 // indirect
21+
github.com/pmezard/go-difflib v1.0.0 // indirect
22+
go.uber.org/multierr v1.11.0 // indirect
23+
golang.org/x/crypto v0.18.0 // indirect
24+
golang.org/x/sys v0.17.0 // indirect
25+
gopkg.in/yaml.v2 v2.4.0 // indirect
26+
gopkg.in/yaml.v3 v3.0.1 // indirect
27+
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000 // indirect
28+
)
29+
530
require (
31+
github.com/cloudflare/circl v1.3.8
32+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
633
github.com/inconshreveable/mousetrap v1.1.0 // indirect
7-
github.com/shopspring/decimal v1.4.0 // indirect
8-
github.com/spf13/cobra v1.8.0 // indirect
34+
github.com/libp2p/go-libp2p v0.33.2
35+
github.com/pkg/errors v0.9.1
36+
github.com/shopspring/decimal v1.4.0
37+
github.com/spf13/cobra v1.8.0
938
github.com/spf13/pflag v1.0.5 // indirect
39+
go.uber.org/zap v1.27.0
40+
google.golang.org/protobuf v1.32.0 // indirect
41+
source.quilibrium.com/quilibrium/monorepo/node v1.14.17
1042
)

0 commit comments

Comments
 (0)