Skip to content

Commit

Permalink
BCCSP Factory support
Browse files Browse the repository at this point in the history
This change-set introduces support for multiple BCCSP factories.
This way, it will be possible to have software-based as well as
hardware-based BCCSP implementations.
The fatory provides also access to a default BCCSP that represents the BCCSP
to be used by default as it is configured via viper.
Tests have been added to test the factories.
This change-set comes in the context of:
https://jira.hyperledger.org/browse/FAB-354

Change-Id: Ib83f1fc31fa0ac77daa76f97684563e4c6e53877
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
  • Loading branch information
adecaro committed Nov 7, 2016
1 parent b3bd3fa commit 8ba61a9
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 0 deletions.
127 changes: 127 additions & 0 deletions core/crypto/bccsp/factory/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
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.
*/
package factory

import (
"errors"
"fmt"
"sync"

"github.com/hyperledger/fabric/core/crypto/bccsp"
"github.com/spf13/viper"
)

var (
// Default BCCSP
defaultBCCSP bccsp.BCCSP

// BCCSP Factories
factories map[string]BCCSPFactory

// factories' Sync on Initialization
factoriesInitOnce sync.Once

// Factories' Initialization Error
factoriesInitError error
)

// BCCSPFactory is used to get instances of the BCCSP interface.
// A Factory has name used to address it.
type BCCSPFactory interface {

// Name returns the name of this factory
Name() string

// Get returns an instance of BCCSP using opts.
Get(opts Opts) (bccsp.BCCSP, error)
}

// Opts contains options for instantiating BCCSPs.
type Opts interface {

// FactoryName returns the name of the factory to be used
FactoryName() string

// Ephemeral returns true if the BCCSP has to be ephemeral, false otherwise
Ephemeral() bool
}

// GetDefault returns a non-ephemeral (long-term) BCCSP
func GetDefault() (bccsp.BCCSP, error) {
if err := initFactories(); err != nil {
return nil, err
}

return defaultBCCSP, nil
}

// GetBCCSP returns a BCCSP created according to the options passed in input.
func GetBCCSP(opts Opts) (bccsp.BCCSP, error) {
if err := initFactories(); err != nil {
return nil, err
}

return getBCCSPInternal(opts)
}

func initFactories() error {
factoriesInitOnce.Do(func() {
// Initialize factories map
if factoriesInitError = initFactoriesMap(); factoriesInitError != nil {
return
}

// Create default non-ephemeral (long-term) BCCSP
defaultBCCSP, factoriesInitError = createDefaultBCCSP()
if factoriesInitError != nil {
return
}
})
return factoriesInitError
}

func initFactoriesMap() error {
factories = make(map[string]BCCSPFactory)

// Software-Based BCCSP
f := &SWFactory{}
factories[f.Name()] = f

return nil
}

func createDefaultBCCSP() (bccsp.BCCSP, error) {
defaultBCCSPFactoryName := viper.GetString("bccsp.default")
if defaultBCCSPFactoryName == "" {
defaultBCCSPFactoryName = SoftwareBasedFactoryName
}

return getBCCSPInternal(&DefaultOpts{defaultBCCSPFactoryName, false})
}

func getBCCSPInternal(opts Opts) (bccsp.BCCSP, error) {
// Validate arguments
if opts == nil {
return nil, errors.New("Cannot instantiate a factory with 'nil' Opts. A fully instantiated BCCSP Opts struct must be provided.")
}

f, ok := factories[opts.FactoryName()]
if ok {
return f.Get(opts)
}

return nil, fmt.Errorf("Factory [%s] does not exist.", opts.FactoryName())
}
32 changes: 32 additions & 0 deletions core/crypto/bccsp/factory/factory_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
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.
*/
package factory

// DefaultOpts offers a default implementation for Opts
type DefaultOpts struct {
ProviderName string
EphemeralFlag bool
}

// FactoryName returns the name of the provider
func (o *DefaultOpts) FactoryName() string {
return o.ProviderName
}

// Ephemeral returns true if the CSP has to be ephemeral, false otherwise
func (o *DefaultOpts) Ephemeral() bool {
return o.EphemeralFlag
}
60 changes: 60 additions & 0 deletions core/crypto/bccsp/factory/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
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.
*/
package factory

import "testing"

func TestGetDefault(t *testing.T) {
bccsp, err := GetDefault()
if err != nil {
t.Fatalf("Failed getting default BCCSP [%s]", err)
}
if bccsp == nil {
t.Fatal("Failed getting default BCCSP. Nil instance.")
}
}

func TestGetBCCPEphemeral(t *testing.T) {
bccsp1, err := GetBCCSP(&SwOpts{EphemeralFlag: true})
if err != nil {
t.Fatalf("Failed getting ephemeral software-based BCCSP [%s]", err)
}

bccsp2, err := GetBCCSP(&SwOpts{EphemeralFlag: true})
if err != nil {
t.Fatalf("Failed getting ephemeral software-based BCCSP [%s]", err)
}

if bccsp1 == bccsp2 {
t.Fatal("Ephemeral BCCSPs should point to different instances")
}
}

func TestGetBCCP2Ephemeral(t *testing.T) {
bccsp1, err := GetBCCSP(&SwOpts{EphemeralFlag: false})
if err != nil {
t.Fatalf("Failed getting non-ephemeral software-based BCCSP [%s]", err)
}

bccsp2, err := GetBCCSP(&SwOpts{EphemeralFlag: false})
if err != nil {
t.Fatalf("Failed getting non-ephemeral software-based BCCSP [%s]", err)
}

if bccsp1 != bccsp2 {
t.Fatal("Non-ephemeral BCCSPs should point to the same instance")
}
}
79 changes: 79 additions & 0 deletions core/crypto/bccsp/factory/sw_factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
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.
*/
package factory

import (
"errors"
"fmt"
"sync"

"github.com/hyperledger/fabric/core/crypto/bccsp"
"github.com/hyperledger/fabric/core/crypto/bccsp/sw"
)

const (
// SoftwareBasedFactoryName is the name of the factory of the software-based BCCSP implementation
SoftwareBasedFactoryName = "SW"
)

// SWFactory is the factory of the software-based BCCSP.
type SWFactory struct {
initOnce sync.Once
bccsp bccsp.BCCSP
err error
}

// Name returns the name of this factory
func (f *SWFactory) Name() string {
return SoftwareBasedFactoryName
}

// Get returns an instance of BCCSP using Opts.
func (f *SWFactory) Get(opts Opts) (bccsp.BCCSP, error) {
// Validate arguments
if opts == nil {
return nil, errors.New("Invalid opts. It must not be nil.")
}

if opts.FactoryName() != f.Name() {
return nil, fmt.Errorf("Invalid Provider Name [%s]. Opts must refer to [%s].", opts.FactoryName(), f.Name())
}

if !opts.Ephemeral() {
f.initOnce.Do(func() {
f.bccsp, f.err = sw.New()
return
})
return f.bccsp, f.err
}

return sw.New()
}

// SwOpts contains options for the SWFactory
type SwOpts struct {
EphemeralFlag bool
}

// FactoryName returns the name of the provider
func (o *SwOpts) FactoryName() string {
return SoftwareBasedFactoryName
}

// Ephemeral returns true if the CSP has to be ephemeral, false otherwise
func (o *SwOpts) Ephemeral() bool {
return o.EphemeralFlag
}

0 comments on commit 8ba61a9

Please sign in to comment.