├── README.md ├── example ├── .gitignore ├── Makefile ├── README.md ├── go.mod ├── go.sum └── main.go ├── go.mod ├── types.go ├── zks_crypto.h ├── zkscrypto.go └── zkscrypto_test.go /README.md: -------------------------------------------------------------------------------- 1 | # ZKSyncSDK for Go 2 | 3 | Cryptographical primitives used in zkSync network. 4 | 5 | 6 | ## Requirements 7 | 8 | - macOS 10.12+ / linux x86_64 / windows x86_64 9 | - go >= 1.15 10 | - libzkscrypto.a 11 | 12 | 13 | ## Installation 14 | 15 | * Import package to your project (use flag `-d` to prevent compiling attempt): 16 | 17 | `go get -d github.com/zksync-sdk/zksync-sdk-go` 18 | * Download binary library for your platform from https://github.com/zksync-sdk/zksync-crypto-c/releases, change downloaded file name to `libzks-crypto` (but keep original file extension) and put it into `./libs` directory of your project 19 | * Build project, using `CGO_LDFLAGS="-L./libs"` environment variable: 20 | 21 | `CGO_LDFLAGS="-L./libs" go build` 22 | 23 | or just export it for current environment: 24 | 25 | ``` 26 | $ export CGO_LDFLAGS="-L./libs" 27 | $ go build 28 | ``` 29 | 30 | 31 | ## License 32 | 33 | The MIT License (MIT) 34 | 35 | Copyright (c) 2020 Matter Labs 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | libs/ 2 | example 3 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | download: 4 | mkdir -p libs 5 | ifeq ($(shell uname -s),Darwin) 6 | test -f ./libs/libzks-crypto.a || curl -L https://github.com/zksync-sdk/zksync-crypto-c/releases/download/v0.1.2/zks-crypto-macos-x64.a --output ./libs/libzks-crypto.a 7 | else 8 | test -f ./libs/libzks-crypto.so || curl -L https://github.com/zksync-sdk/zksync-crypto-c/releases/download/v0.1.2/zks-crypto-linux-x64.so --output ./libs/libzks-crypto.so 9 | endif 10 | 11 | build: download 12 | test -f example || CGO_LDFLAGS="-L./libs" go build 13 | 14 | run: build 15 | ifeq ($(shell uname -s),Darwin) 16 | ./example 17 | else 18 | LD_LIBRARY_PATH=./libs ./example 19 | endif -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # ZKSyncSDK for Go usage example 2 | 3 | This simple test project show example of usage of imported package. 4 | 5 | ## Quick run 6 | 7 | For macOS and Linux just run make: 8 | ``` 9 | $ make 10 | ``` 11 | 12 | This will download required binary library for your platform, build and run example. -------------------------------------------------------------------------------- /example/go.mod: -------------------------------------------------------------------------------- 1 | module example 2 | 3 | go 1.16 4 | 5 | require github.com/zksync-sdk/zksync-sdk-go v0.0.0-20210423071041-006032f36311 6 | -------------------------------------------------------------------------------- /example/go.sum: -------------------------------------------------------------------------------- 1 | github.com/zksync-sdk/zksync-sdk-go v0.0.0-20210423071041-006032f36311 h1:9X4JqklD3BqU3xtYInVOYm3KRskyfvtuXMQ1s8UNwuI= 2 | github.com/zksync-sdk/zksync-sdk-go v0.0.0-20210423071041-006032f36311/go.mod h1:ZUgHa5wGdUAYfBlO6iEL3UV/IVTiKNI4JuWlLnbBpWM= 3 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/hex" 5 | "log" 6 | 7 | "github.com/zksync-sdk/zksync-sdk-go" 8 | ) 9 | 10 | func main() { 11 | seed := make([]byte, 32) 12 | message := []byte("hello") 13 | 14 | privateKey, err := zkscrypto.NewPrivateKey(seed) 15 | if err != nil { 16 | log.Fatalf("error creating private key: %s", err.Error()) 17 | } 18 | publicKey, err := privateKey.PublicKey() 19 | if err != nil { 20 | log.Fatalf("error creating public key: %s", err.Error()) 21 | } 22 | publicKeyHash, err := publicKey.Hash() 23 | if err != nil { 24 | log.Fatalf("error creating public key hash: %s", err.Error()) 25 | } 26 | signature, err := privateKey.Sign(message) 27 | if err != nil { 28 | log.Fatalf("error signing message: %s", err.Error()) 29 | } 30 | log.Printf("Seed: %s\n", hex.EncodeToString(seed)) 31 | log.Printf("Private key: %s\n", privateKey.HexString()) 32 | log.Printf("Public key: %s\n", publicKey.HexString()) 33 | log.Printf("Public key hash: %s\n", publicKeyHash.HexString()) 34 | log.Printf("Signature: %s\n", signature.HexString()) 35 | } 36 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/zksync-sdk/zksync-sdk-go 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package zkscrypto 2 | 3 | // PrivateKey represents a private key. 4 | type PrivateKey struct { 5 | data []byte 6 | } 7 | 8 | // PublicKey represents a public key 9 | type PublicKey struct { 10 | data []byte 11 | } 12 | 13 | // PublicKeyHash represents a public key hash 14 | type PublicKeyHash struct { 15 | data []byte 16 | } 17 | 18 | // Signature represents a multi-signature 19 | type Signature struct { 20 | data []byte 21 | } 22 | 23 | // ResqueHash represents a resque hash of orders 24 | type ResqueHash struct { 25 | data []byte 26 | } 27 | -------------------------------------------------------------------------------- /zks_crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef ZKS_CRYPTO_H 2 | #define ZKS_CRYPTO_H 3 | 4 | /* Generated with cbindgen:0.14.3 */ 5 | 6 | /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | /** 15 | * Maximum byte length of the message that can be signed. 16 | */ 17 | #define MAX_SIGNED_MESSAGE_LEN 92 18 | 19 | /** 20 | * Byte length of the signature. Signature contains r and s points. 21 | */ 22 | #define PACKED_SIGNATURE_LEN 64 23 | 24 | /** 25 | * Byte length of the private key 26 | */ 27 | #define PRIVATE_KEY_LEN 32 28 | 29 | /** 30 | * Byte length of the public key hash 31 | */ 32 | #define PUBKEY_HASH_LEN 20 33 | 34 | /** 35 | * Byte length of the public key 36 | */ 37 | #define PUBLIC_KEY_LEN 32 38 | 39 | /** 40 | * Maximum byte length of the rescue hash. 41 | */ 42 | #define RESCUE_HASH_LEN 31 43 | 44 | typedef enum MUSIG_SIGN_RES { 45 | MUSIG_SIGN_OK = 0, 46 | MUSIG_SIGN_MSG_TOO_LONG, 47 | } MUSIG_SIGN_RES; 48 | 49 | typedef enum MUSIG_VERIFY_RES { 50 | MUSIG_VERIFY_OK = 0, 51 | MUSIG_VERIFY_FAILED, 52 | } MUSIG_VERIFY_RES; 53 | 54 | typedef enum PRIVATE_KEY_FROM_SEED_RES { 55 | PRIVATE_KEY_FROM_SEED_OK = 0, 56 | /** 57 | * Seed should be at least 32 bytes long 58 | */ 59 | PRIVATE_KEY_FROM_SEED_SEED_TOO_SHORT, 60 | } PRIVATE_KEY_FROM_SEED_RES; 61 | 62 | typedef enum PUBKEY_HASH_FROM_PUBKEY_RES { 63 | PUBKEY_HASH_FROM_PUBKEY_OK = 0, 64 | } PUBKEY_HASH_FROM_PUBKEY_RES; 65 | 66 | typedef enum PUBLIC_KEY_FROM_PRIVATE_RES { 67 | PUBLIC_KEY_FROM_PRIVATE_OK = 0, 68 | } PUBLIC_KEY_FROM_PRIVATE_RES; 69 | 70 | typedef struct ZksResqueHash { 71 | uint8_t data[RESCUE_HASH_LEN]; 72 | } ZksResqueHash; 73 | 74 | typedef struct ZksPrivateKey { 75 | uint8_t data[PRIVATE_KEY_LEN]; 76 | } ZksPrivateKey; 77 | 78 | typedef struct ZksPackedPublicKey { 79 | uint8_t data[PUBLIC_KEY_LEN]; 80 | } ZksPackedPublicKey; 81 | 82 | typedef struct ZksPubkeyHash { 83 | uint8_t data[PUBKEY_HASH_LEN]; 84 | } ZksPubkeyHash; 85 | 86 | typedef struct ZksSignature { 87 | uint8_t data[PACKED_SIGNATURE_LEN]; 88 | } ZksSignature; 89 | 90 | void rescue_hash_orders(const uint8_t *msg, size_t msg_len, ZksResqueHash *hash); 91 | 92 | /** 93 | * Initializes thread local storage of the parameters used for calculations. 94 | * Calling this before other calls is optional since parameters will be initialized when needed. 95 | * Can save time for the first call of other functions in the thread 96 | * since it takes time to init parameters. 97 | */ 98 | void zks_crypto_init(void); 99 | 100 | PRIVATE_KEY_FROM_SEED_RES zks_crypto_private_key_from_seed(const uint8_t *seed, 101 | size_t seed_len, 102 | ZksPrivateKey *private_key); 103 | 104 | PUBLIC_KEY_FROM_PRIVATE_RES zks_crypto_private_key_to_public_key(const ZksPrivateKey *private_key, 105 | ZksPackedPublicKey *public_key); 106 | 107 | PUBKEY_HASH_FROM_PUBKEY_RES zks_crypto_public_key_to_pubkey_hash(const ZksPackedPublicKey *public_key, 108 | ZksPubkeyHash *pubkey_hash); 109 | 110 | /** 111 | * We use musig Schnorr signature scheme. 112 | * It is impossible to restore signer for signature, that is why we provide public key of the signer 113 | * along with signature. 114 | * [0..32] - packed r point of the signature. 115 | * [32..64] - s point of the signature. 116 | */ 117 | MUSIG_SIGN_RES zks_crypto_sign_musig(const ZksPrivateKey *private_key, 118 | const uint8_t *msg, 119 | size_t msg_len, 120 | ZksSignature *signature_output); 121 | 122 | MUSIG_VERIFY_RES zks_crypto_verify_musig(const uint8_t *msg, 123 | size_t msg_len, 124 | const ZksPackedPublicKey *public_key, 125 | const ZksSignature *signature); 126 | 127 | #endif /* ZKS_CRYPTO_H */ 128 | -------------------------------------------------------------------------------- /zkscrypto.go: -------------------------------------------------------------------------------- 1 | package zkscrypto 2 | 3 | /* 4 | #cgo LDFLAGS: -lzks-crypto 5 | 6 | #include "zks_crypto.h" 7 | */ 8 | import "C" 9 | import ( 10 | "encoding/hex" 11 | "errors" 12 | "unsafe" 13 | ) 14 | 15 | var ( 16 | errSeedLen = errors.New("given seed is too short, length must be greater than 32") 17 | errPrivateKey = errors.New("error on private key generation") 18 | errPrivateKeyLen = errors.New("raw private key must be exactly 32 bytes") 19 | errSignedMsgLen = errors.New("musig message length must not be larger than 92") 20 | errSign = errors.New("error on sign message") 21 | ) 22 | 23 | func init() { 24 | C.zks_crypto_init() 25 | } 26 | 27 | /* 28 | ************************************************************************************************ 29 | Private key implementation 30 | ************************************************************************************************ 31 | */ 32 | 33 | // NewPrivateKey generates private key from seed 34 | func NewPrivateKey(seed []byte) (*PrivateKey, error) { 35 | pointer := C.struct_ZksPrivateKey{} 36 | rawSeed := C.CBytes(seed) 37 | defer C.free(rawSeed) 38 | result := C.zks_crypto_private_key_from_seed((*C.uint8_t)(rawSeed), C.size_t(len(seed)), &pointer) 39 | if result != 0 { 40 | switch result { 41 | case 1: 42 | return nil, errSeedLen 43 | default: 44 | return nil, errPrivateKey 45 | } 46 | } 47 | data := unsafe.Pointer(&pointer.data) 48 | return &PrivateKey{data: C.GoBytes(data, C.PRIVATE_KEY_LEN)}, nil 49 | } 50 | 51 | // NewPrivateKeyRaw create private key from raw bytes 52 | func NewPrivateKeyRaw(pk []byte) (*PrivateKey, error) { 53 | if len(pk) != C.PRIVATE_KEY_LEN { 54 | return nil, errPrivateKeyLen 55 | } 56 | return &PrivateKey{data: pk}, nil 57 | } 58 | 59 | // GetBytes return private key raw bytes 60 | func (pk *PrivateKey) GetBytes() []byte { 61 | return pk.data 62 | } 63 | 64 | // Sign message with musig Schnorr signature scheme 65 | func (pk *PrivateKey) Sign(message []byte) (*Signature, error) { 66 | privateKeyC := C.struct_ZksPrivateKey{} 67 | rawMessage := C.CBytes(message) 68 | defer C.free(rawMessage) 69 | for i := range pk.data { 70 | privateKeyC.data[i] = C.uint8_t(pk.data[i]) 71 | } 72 | signatureC := C.struct_ZksSignature{} 73 | result := C.zks_crypto_sign_musig(&privateKeyC, (*C.uint8_t)(rawMessage), C.size_t(len(message)), &signatureC) 74 | if result != 0 { 75 | switch result { 76 | case 1: 77 | return nil, errSignedMsgLen 78 | default: 79 | return nil, errSign 80 | } 81 | } 82 | data := unsafe.Pointer(&signatureC.data) 83 | return &Signature{data: C.GoBytes(data, C.PACKED_SIGNATURE_LEN)}, nil 84 | } 85 | 86 | // PublicKey generates public key from private key 87 | func (pk *PrivateKey) PublicKey() (*PublicKey, error) { 88 | privateKeyC := C.struct_ZksPrivateKey{} 89 | for i := range pk.data { 90 | privateKeyC.data[i] = C.uint8_t(pk.data[i]) 91 | } 92 | pointer := C.struct_ZksPackedPublicKey{} 93 | result := C.zks_crypto_private_key_to_public_key(&privateKeyC, &pointer) 94 | if result != 0 { 95 | return nil, errors.New("error on public key generation") 96 | } 97 | data := unsafe.Pointer(&pointer.data) 98 | return &PublicKey{data: C.GoBytes(data, C.PUBLIC_KEY_LEN)}, nil 99 | } 100 | 101 | // HexString creates a hex string representation of a private key 102 | func (pk *PrivateKey) HexString() string { 103 | if pk.data == nil || len(pk.data) == 0 { 104 | return "0x" 105 | } 106 | return hex.EncodeToString(pk.data) 107 | } 108 | 109 | /* 110 | ************************************************************************************************ 111 | Public key implementation 112 | ************************************************************************************************ 113 | */ 114 | 115 | // Hash generates hash from public key 116 | func (pk *PublicKey) Hash() (*PublicKeyHash, error) { 117 | publicKeyC := C.struct_ZksPackedPublicKey{} 118 | for i := range pk.data { 119 | publicKeyC.data[i] = C.uint8_t(pk.data[i]) 120 | } 121 | pointer := C.struct_ZksPubkeyHash{} 122 | result := C.zks_crypto_public_key_to_pubkey_hash(&publicKeyC, &pointer) 123 | if result != 0 { 124 | return nil, errors.New("Error on public key hash generation") 125 | } 126 | data := unsafe.Pointer(&pointer.data) 127 | return &PublicKeyHash{data: C.GoBytes(data, C.PUBKEY_HASH_LEN)}, nil 128 | } 129 | 130 | // HexString creates a hex string representation of a public key 131 | func (pk *PublicKey) HexString() string { 132 | if pk.data == nil || len(pk.data) == 0 { 133 | return "0x" 134 | } 135 | return hex.EncodeToString(pk.data) 136 | } 137 | 138 | /* 139 | ************************************************************************************************ 140 | ResqueHash implementation 141 | ************************************************************************************************ 142 | */ 143 | 144 | // ResqueHashOrders generates hash from orders bytes 145 | func ResqueHashOrders(orders []byte) *ResqueHash { 146 | pointer := C.struct_ZksResqueHash{} 147 | rawOrders := C.CBytes(orders) 148 | defer C.free(rawOrders) 149 | C.rescue_hash_orders((*C.uint8_t)(rawOrders), C.size_t(len(orders)), &pointer) 150 | data := unsafe.Pointer(&pointer.data) 151 | return &ResqueHash{data: C.GoBytes(data, C.RESCUE_HASH_LEN)} 152 | } 153 | 154 | // GetBytes return resque hash raw bytes 155 | func (rh *ResqueHash) GetBytes() []byte { 156 | return rh.data 157 | } 158 | 159 | /* 160 | ************************************************************************************************ 161 | Private key Hash implementation 162 | ************************************************************************************************ 163 | */ 164 | 165 | // HexString creates a hex string representation of a public key hash 166 | func (pk *PublicKeyHash) HexString() string { 167 | if pk.data == nil || len(pk.data) == 0 { 168 | return "0x" 169 | } 170 | return hex.EncodeToString(pk.data) 171 | } 172 | 173 | /* 174 | ************************************************************************************************ 175 | Signature implementation 176 | ************************************************************************************************ 177 | */ 178 | 179 | // HexString creates a hex string representation of a signature 180 | func (pk *Signature) HexString() string { 181 | if pk.data == nil || len(pk.data) == 0 { 182 | return "0x" 183 | } 184 | return hex.EncodeToString(pk.data) 185 | } 186 | -------------------------------------------------------------------------------- /zkscrypto_test.go: -------------------------------------------------------------------------------- 1 | package zkscrypto 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestPrivateKeyGeneration(t *testing.T) { 9 | seed := make([]byte, 32) 10 | expected := []byte{1, 31, 91, 153, 8, 76, 92, 46, 45, 94, 99, 72, 142, 15, 113, 104, 213, 153, 165, 192, 31, 233, 254, 196, 201, 150, 5, 116, 61, 165, 232, 92} 11 | privateKey, err := NewPrivateKey(seed) 12 | if err != nil { 13 | t.Fatalf("%s", err.Error()) 14 | } 15 | if !bytes.Equal(privateKey.data, expected) { 16 | t.Fatalf("%s,%v,%v must be equal to %v", "Unexpected private key", seed, privateKey.data, expected) 17 | } 18 | } 19 | 20 | func TestPublicKeyGenerationFromPrivateKey(t *testing.T) { 21 | privateKeyRaw := []byte{1, 31, 91, 153, 8, 76, 92, 46, 45, 94, 99, 72, 142, 15, 113, 104, 213, 153, 165, 192, 31, 233, 254, 196, 201, 150, 5, 116, 61, 165, 232, 92} 22 | expected := []byte{23, 156, 58, 89, 20, 125, 48, 49, 108, 136, 102, 40, 133, 35, 72, 201, 180, 42, 24, 184, 33, 8, 74, 201, 239, 121, 189, 115, 233, 185, 78, 141} 23 | pk := PrivateKey{data: privateKeyRaw} 24 | 25 | publicKey, err := pk.PublicKey() 26 | if err != nil { 27 | t.Fatalf("%s", err.Error()) 28 | } 29 | if !bytes.Equal(publicKey.data, expected) { 30 | t.Fatalf("%s,%v must be equal to %v", "Unexpected public key", publicKey.data, expected) 31 | } 32 | } 33 | 34 | func TestHashGenerationFromPublicKey(t *testing.T) { 35 | publicKeyRaw := []byte{23, 156, 58, 89, 20, 125, 48, 49, 108, 136, 102, 40, 133, 35, 72, 201, 180, 42, 24, 184, 33, 8, 74, 201, 239, 121, 189, 115, 233, 185, 78, 141} 36 | expected := []byte{199, 113, 39, 22, 185, 239, 107, 210, 23, 83, 196, 233, 29, 236, 195, 81, 177, 17, 192, 109} 37 | pk := PublicKey{data: publicKeyRaw} 38 | 39 | publicKeyHash, err := pk.Hash() 40 | if err != nil { 41 | t.Fatalf("%s", err.Error()) 42 | } 43 | if !bytes.Equal(publicKeyHash.data, expected) { 44 | t.Fatalf("%s,%v must be equal to %v", "Unexpected public key hash", publicKeyHash.data, expected) 45 | } 46 | } 47 | 48 | func TestSigningMessageUsingPrivateKey(t *testing.T) { 49 | privateKeyRaw := []byte{1, 31, 91, 153, 8, 76, 92, 46, 45, 94, 99, 72, 142, 15, 113, 104, 213, 153, 165, 192, 31, 233, 254, 196, 201, 150, 5, 116, 61, 165, 232, 92} 50 | message := []byte("hello") 51 | expected := []byte{66, 111, 115, 126, 202, 53, 46, 252, 88, 149, 33, 63, 156, 220, 202, 144, 162, 98, 68, 248, 76, 194, 149, 192, 31, 0, 20, 92, 6, 200, 13, 37, 62, 28, 185, 253, 66, 183, 96, 128, 196, 211, 32, 85, 182, 137, 234, 62, 1, 229, 111, 152, 128, 227, 145, 47, 155, 27, 153, 193, 228, 91, 80, 4} 52 | pk := PrivateKey{data: privateKeyRaw} 53 | 54 | signature, err := pk.Sign(message) 55 | if err != nil { 56 | t.Fatalf("%s", err.Error()) 57 | } 58 | if !bytes.Equal(signature.data, expected) { 59 | t.Fatalf("%s,%v must be equal to %v", "Unexpected signature", signature.data, expected) 60 | } 61 | } 62 | --------------------------------------------------------------------------------