Skip to content

Commit

Permalink
Merge pull request dashpay#28 from shotonoff/TD-17-upgrade-go-binding…
Browse files Browse the repository at this point in the history
…s-to-upstream-v1.0.7

TD-17 Upgrade go-bindings to upstream v1.0.7
  • Loading branch information
QuantumExplorer authored Jan 10, 2022
2 parents 979f423 + 680d126 commit 7a690fd
Show file tree
Hide file tree
Showing 28 changed files with 3,190 additions and 2 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,21 @@ jobs:
- name: Test pure python implementation
run: |
python python-impl/impl-test.py
- name: Install emsdk
uses: mymindstorm/setup-emsdk@v9

- name: Test javascript bindings
run: |
emcc -v
sh emsdk_build.sh
sh js_test.sh
- uses: actions/setup-go@v2
with:
go-version: "^1.17"

- name: Test go bindings
run: |
cd go-bindings
make
1 change: 1 addition & 0 deletions go-bindings/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!Makefile
46 changes: 46 additions & 0 deletions go-bindings/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
SRC_DIR=$(PWD)/../src
BUILD_DIR=$(PWD)/../build
CACHE_DIR=$(PWD)/cache

CGO_LDFLAGS="-L$(CACHE_DIR)/lib -lbls-dash -lrelic_s -lgmp"
CGO_CXXFLAGS="-I$(CACHE_DIR)"

GO="go"
COVERAGE_OUTPUT ?= coverage.out

.PHONY: default vet test clean

default: prepare vet test clean

prepare:
ifeq ("$(wildcard $(CACHE_DIR))", "")
@mkdir -p $(CACHE_DIR)/bls-dash
@mkdir -p $(CACHE_DIR)/lib
@find $(BUILD_DIR) -name "*.a" -exec cp {} $(CACHE_DIR)/lib \;
@cp -r $(BUILD_DIR)/_deps/relic-src/include/* $(CACHE_DIR)
@cp -r $(BUILD_DIR)/_deps/relic-build/include/* $(CACHE_DIR)
@cp -r $(SRC_DIR)/* $(CACHE_DIR)/bls-dash
endif

fmt: ## Run go fmt to format Go files
$(GO) fmt

test: ## Run a basic test suite
CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) $(GO) test

cover: ## Run tests and generate test coverage file, output coverage results and HTML coverage file.
CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) $(GO) test -coverprofile $(COVERAGE_OUTPUT)
CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) $(GO) tool cover -func=$(COVERAGE_OUTPUT)
CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) $(GO) tool cover -html=$(COVERAGE_OUTPUT)
rm -f $(COVERAGE_OUTPUT)

vet: ## Go vet all project code
CGO_CXXFLAGS=$(CGO_CXXFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) go vet ./...

help: ## Show This Help
@for line in $$(cat Makefile | grep "##" | grep -v "grep" | sed "s/:.*##/:/g" | sed "s/\ /!/g"); do verb=$$(echo $$line | cut -d ":" -f 1); desc=$$(echo $$line | cut -d ":" -f 2 | sed "s/!/\ /g"); printf "%-30s--%s\n" "$$verb" "$$desc"; done

clean: ## Clean up transient (generated) files
$(GO) clean
rm -f $(COVERAGE_OUTPUT)
rm -rf $(CACHE_DIR)
195 changes: 195 additions & 0 deletions go-bindings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
## bls-signatures

Go library that implements BLS signatures with aggregation as
in [Boneh, Drijvers, Neven 2018](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html), using the relic
toolkit for cryptographic primitives (pairings, EC, hashing).

This library is a Go port of the [Chia Network's BLS lib](https://github.com/Chia-Network/bls-signatures).

### Usage

```bash
go get github.com/dashpay/bls-signatures/go-bindings
```

### Creating keys and signatures

```go
// seed data must not be less 32 bytes length
seed := []byte{
0, 50, 6, 244, 24, 199, 1, 25,
52, 88, 192, 19, 18, 12, 89, 6,
220, 18, 102, 58, 209, 82, 12, 62,
89, 110, 182, 9, 44, 20, 254, 22,
}

// create a scheme, available three schemes: BasicSchemeMPL, AugSchemeMPL and PopSchemeMPL
scheme := NewAugSchemeMPL()

// generate a private key using a seed data
sk, err := scheme.KeyGen(seed)
if err != nil {
panic(err.Error())
}
// get a public key
pk, err := sk.G1Element()
if err != nil {
panic(err.Error())
}

msg := []byte{1, 2, 3, 4, 5}

// make a signature for a message
sig := scheme.Sign(sk, msg)

// verify the message signature
if !scheme.Verify(pk, msg, sig) {
panic("failed the signature verification")
}
```

### Serializing keys and signatures to bytes

```go
skBytes := sk.Serialize()
pkBytes := pk.Serialize()
sigBytes := sig.Serialize()
```

### Loading keys and signatures from bytes

```go
sk1, _ := PrivateKeyFromBytes(skBytes, false)
pk1, _ := G1ElementFromBytes(pkBytes)
sig1, _ := G2ElementFromBytes(sigBytes)
```

### Create aggregate signatures

```go
// Generate some more private keys
seed[0] = 1
sk1, _ := scheme.KeyGen(seed)
seed[0] = 2
sk2, _ := scheme.KeyGen(seed)
msg2 := []byte{1, 2, 3, 4, 5,6, 7}

// Generate first sig
pk1, _ := sk1.G1Element()
sig1 := scheme.Sign(sk1, msg)

// Generate second sig
pk2, _ := sk2.G1Element()
sig2 := scheme.Sign(sk2, msg2)

// Signatures can be non-interactively combined by anyone
var aggSig = scheme.AggregateSigs(sig1, sig2)

ok := scheme.AggregateVerify([]*G1Element{pk1, pk2}, [][]byte{msg, msg2}, aggSig)
if !ok {
panic("failed a verification of the aggregated signature ")
}
```

### Arbitrary trees of aggregates

```go
seed[0] = 3
sk3, _ := scheme.KeyGen(seed)
pk3, _ := sk3.G1Element()
msg3 := []byte{100, 2, 254, 88, 90, 45, 23}
sig3 := scheme.Sign(sk3, msg3)

aggSigFinal := scheme.AggregateSigs(aggSig, sig3)
ok = scheme.AggregateVerify([]*G1Element{pk1, pk2, pk3}, [][]byte{msg, msg2, msg3}, aggSigFinal)
if !ok {
panic("failed a verification of the aggregated signature ")
}
```

### Very fast verification with Proof of Possession scheme

```go
// create a proof possession scheme
popScheme := NewPopSchemeMPL()

// If the same msg is signed, you can use Proof of Possession (PopScheme) for efficiency
// A proof of possession MUST be passed around with the PK to ensure security.
popSig1 := popScheme.Sign(sk1, msg)
popSig2 := popScheme.Sign(sk2, msg)
popSig3 := popScheme.Sign(sk3, msg)
pop1 := popScheme.PopProve(sk1)
pop2 := popScheme.PopProve(sk2)
pop3 := popScheme.PopProve(sk3)

ok = popScheme.PopVerify(pk1, pop1)
if !ok {
panic("failed a verification")
}
ok = popScheme.PopVerify(pk2, pop2)
if !ok {
panic("failed a verification")
}
ok = popScheme.PopVerify(pk3, pop3)
if !ok {
panic("failed a verification")
}

popSigAgg := popScheme.AggregateSigs(popSig1, popSig2, popSig3)
ok = popScheme.FastAggregateVerify([]*G1Element{pk1, pk2, pk3}, msg, popSigAgg)
if !ok {
panic("failed a verification")
}

// Aggregate public key, indistinguishable from a single public key
var popAggPk = pk1.Add(pk2).Add(pk3)
ok = popScheme.Verify(popAggPk, msg, popSigAgg)
if !ok {
panic("failed a verification")
}

// Aggregate private keys
var aggSk = PrivateKeyAggregate(sk1, sk2, sk3)
ok = popScheme.Sign(aggSk, msg).EqualTo(popSigAgg)
if !ok {
panic("failed a verification")
}
```

### HD keys using [EIP-2333](https://github.com/ethereum/EIPs/pull/2333)

```go
// You can derive 'child' keys from any key, to create arbitrary trees. 4 byte indeces are used.
// Hardened (more secure, but no parent pk -> child pk)
masterSk, _ := augScheme.KeyGen(seed)

// Unhardened (less secure, but can go from parent pk -> child pk), BIP32 style
masterPk, _ := masterSk.G1Element()
childU := augScheme.DeriveChildSkUnhardened(masterSk, 22)
grandchildU := augScheme.DeriveChildSkUnhardened(childU, 0)

childUPk := augScheme.DeriveChildPkUnhardened(masterPk, 22)
grandchildUPk := augScheme.DeriveChildPkUnhardened(childUPk, 0)

pkChildU, _ := grandchildU.G1Element()
ok = grandchildUPk.EqualTo(pkChildU)
if !ok {
panic("keys are not equal")
}
```

Do not forget to handle the errors properly, this part of the code was omitted deliberately

Use cases can be found in the [original lib's readme](../README.md).

__Important note:__ Since this library is a port of the c++ library, so every piece of memory allocated by the library
MUST be released on our own in GO. To release the memory is used `runtime.SetFinalizer` function, that will invoke
automatically before GC release a memory allocated by GO.

### Run tests

To run tests, build the library, then go to the `go-bindings` folder in the build directory and run

```bash
make test
```
54 changes: 54 additions & 0 deletions go-bindings/blschia.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) 2021 The Dash Core developers

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <stdlib.h>
#include "bls-dash/bls.hpp"
#include "error.h"
#include "blschia.h"

std::string gErrMsg;

void SecFree(void *p) {
bls::Util::SecFree(p);
}

void** AllocPtrArray(size_t len) {
// caller to free
return (void**)bls::Util::SecAlloc<uint8_t>(sizeof(void*) * len);
}

void SetPtrArray(void** arrPtr, void* elemPtr, int index) {
arrPtr[index] = elemPtr;
}

void FreePtrArray(void** inPtr) {
bls::Util::SecFree(inPtr);
}

void* GetPtrAtIndex(void** arrPtr, int index) {
return arrPtr[index];
}

uint8_t* SecAllocBytes(size_t len) {
return (uint8_t*)bls::Util::SecAlloc<uint8_t>(sizeof(uint8_t) * len);
}

void* GetAddressAtIndex(uint8_t* ptr, int index) {
return (void*)&ptr[index];
}

const char* GetLastErrorMsg() {
return gErrMsg.c_str();
}
46 changes: 46 additions & 0 deletions go-bindings/blschia.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2021 The Dash Core developers

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GO_BINDINGS_BLSCHIA_H_
#define GO_BINDINGS_BLSCHIA_H_
#include <stdbool.h>
#include <stdint.h>
#include "privatekey.h"

#ifdef __cplusplus
extern "C" {
#endif

// Export the BLS SecFree method
void SecFree(void *p);

typedef void** carr;

// Additional C++ helper funcs for allocations
void** AllocPtrArray(size_t len);
void SetPtrArray(void **arrPtr, void *elemPtr, int index);
void FreePtrArray(void **inPtr);
void* GetPtrAtIndex(void **arrPtr, int index);

// Allocates an array of bytes with size of passed in len argument
uint8_t* SecAllocBytes(size_t len);

void* GetAddressAtIndex(uint8_t *ptr, int index);

const char* GetLastErrorMsg();

#ifdef __cplusplus
}
#endif
#endif // GO_BINDINGS_BLSCHIA_H_
Loading

0 comments on commit 7a690fd

Please sign in to comment.