-
Notifications
You must be signed in to change notification settings - Fork 32
MSP curve is hardcoded in constructor, ignoring IdemixMSPConfig.CurveId #85 #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
adecaro
merged 2 commits into
main
from
85-msp-curve-is-hardcoded-in-constructor-ignoring-idemixmspconfigcurveid
Jul 8, 2026
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| This file provides guidance to agents when working with code in this repository. | ||
|
|
||
| ## What this project is | ||
|
|
||
| A Go implementation of an anonymous identity stack (Identity Mixer / Idemix) for blockchain systems, originally designed for use with Hyperledger Fabric. It provides zero-knowledge proof-based credentials: users can prove possession of a CA-signed credential and selectively disclose attributes (OU, Role, EnrollmentID, RevocationHandle) without revealing their identity. | ||
|
|
||
| ## Commands | ||
|
|
||
| ```bash | ||
| # CI entry point: checks + unit-tests + unit-tests-race | ||
| make all | ||
|
|
||
| # Format, vet, and license-header check | ||
| make checks # runs check-deps, gofmt, go vet, addlicense -check | ||
| make fmt # apply gofmt -l -s -w in place | ||
|
|
||
| # Tests | ||
| make unit-tests # go test ./... | ||
| make unit-tests-race # go test -race -cover with GORACE=history_size=7, 960s timeout | ||
|
|
||
| # Run a single package or test directly | ||
| go test ./bccsp/schemes/aries/... | ||
| go test ./bccsp/schemes/aries/ -run TestSignerSign | ||
|
|
||
| # Build idemixgen tool | ||
| make idemixgen # go install ./tools/idemixgen → $GOPATH/bin | ||
| make binaries # cross-compile to bin/amd64/ (linux) and bin/arm64/ (darwin) | ||
|
|
||
| # Protobuf regeneration | ||
| make installbuf # installs buf@v1.70.0 | ||
| make genprotos # buf generate --template buf.gen.yaml | ||
|
|
||
| # Tidy modules | ||
| make tidy | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Two cryptographic schemes | ||
|
|
||
| The codebase implements two parallel cryptographic backends, both exposed through the same BCCSP interface: | ||
|
|
||
| 1. **Legacy / dlog** (`bccsp/schemes/dlog/`) — The original Idemix implementation using discrete log proofs. It takes a `*math.Curve` and a `Translator` (handles curve-specific serialization). Instantiated via `idemix.New(keyStore, curve, translator, exportable)`. | ||
|
|
||
| 2. **Aries** (`bccsp/schemes/aries/`) — A newer implementation using BBS+ signatures for credential issuance, intended to replace the dlog scheme. Instantiated via `idemix.NewAries(keyStore, curve, translator, exportable)`. | ||
|
|
||
| The **legacy guard** in CI enforces that new code must not add new imports of `schemes/dlog` or `schemes/weak-bb` outside of the known files listed in `.github/workflows/go.yml`. New code should use the Aries scheme. | ||
|
|
||
| ### Package structure | ||
|
|
||
| ``` | ||
| bccsp/ | ||
| types/ # Interfaces: Issuer, User, CredRequest, Credential, SignatureScheme, etc. | ||
| handlers/ # BCCSP operation wrappers: IssuerKeyGen, UserKeyGen, Signer, Verifier, etc. | ||
| keystore/ # Key storage implementations | ||
| schemes/ | ||
| aries/ # Aries/BBS+ implementation of all bccsp/types interfaces | ||
| dlog/ | ||
| bridge/ # Adapts dlog/crypto to bccsp/types interfaces | ||
| crypto/ # Core dlog Idemix math (signature, credential, nym, revocation) | ||
| weak-bb/ # Weak Boneh-Boyen signatures (used internally for revocation) | ||
| bccsp.go # New() and NewAries() constructors; multiplexer wiring | ||
| impl.go # CSP base: type-keyed dispatch maps for KeyGen/Sign/Verify/etc. | ||
|
|
||
| bbs/ # BBS+ signature implementation (used by aries/Cred) | ||
|
|
||
| msp/ # Hyperledger Fabric MSP integration: credential lifecycle, | ||
| # attribute indices (OU=0, Role=1, EnrollmentID=2, RevocationHandle=3) | ||
|
|
||
| tools/idemixgen/ # CLI tool to generate issuer keys and signer configs for Fabric MSP | ||
| ``` | ||
|
|
||
| ### BCCSP dispatch pattern | ||
|
|
||
| `CSP` (in `bccsp/impl.go`) is a generic dispatcher that holds `map[reflect.Type]Signer` (and similar maps for KeyGen/Verify/Import/Deriv). Operations are routed by the Go type of the key or opts argument. `bccsp.go` wires concrete scheme implementations into these maps via `AddWrapper`. The `userSecreKeySignerMultiplexer` and `issuerPublicKeyVerifierMultiplexer` types handle cases where a single key type handles multiple opt types. | ||
|
|
||
| ### Curve and translator | ||
|
|
||
| `github.com/IBM/mathlib` provides the elliptic curve abstractions (`*math.Curve`, `*math.G1`, `*math.G2`, `*math.Zr`). The `Translator` interface (dlog scheme) handles curve-specific protobuf serialization for group elements. The `bccsp/schemes/dlog/crypto/translator/amcl/` package provides concrete translators for each supported curve family (FP256BN, BLS12-381, etc.). | ||
|
|
||
| ### Credential attributes | ||
|
|
||
| The four fixed attributes are accessed by index: OU (0), Role (1), EnrollmentID (2), RevocationHandle (3). These indices are referenced throughout `msp/` and must match across signing and verification. | ||
|
|
||
| ### Protobuf | ||
|
|
||
| `.proto` files live alongside their generated `.pb.go` files. Run `make genprotos` (requires `buf`) to regenerate. The main proto files are `bccsp/schemes/dlog/crypto/idemix.proto` and `bccsp/schemes/aries/cred.proto`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| @AGENTS.md | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ import ( | |
|
|
||
| idemix "github.com/IBM/idemix/bccsp" | ||
| "github.com/IBM/idemix/bccsp/keystore" | ||
| idemixcrypto "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" | ||
| "github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl" | ||
| bccsp "github.com/IBM/idemix/bccsp/types" | ||
| im "github.com/IBM/idemix/msp/config" | ||
|
|
@@ -69,6 +70,59 @@ const ( | |
| const rhIndex = 3 | ||
| const eidIndex = 2 | ||
|
|
||
| // Curve ID string constants matching the values written by idemixgen into IdemixMSPConfig.CurveId. | ||
| const ( | ||
| curveIDFP256BN_AMCL = "FP256BN_AMCL" | ||
| curveIDBN254 = "BN254" | ||
| curveIDFP256BN_AMCL_MIRACL = "FP256BN_AMCL_MIRACL" | ||
| curveIDBLS12_377_GURVY = "BLS12_377_GURVY" | ||
| curveIDBLS12_381_GURVY = "BLS12_381_GURVY" | ||
| curveIDBLS12_381 = "BLS12_381" | ||
| curveIDBLS12_381_BBS = "BLS12_381_BBS" | ||
| curveIDBLS12_381_BBS_GURVY = "BLS12_381_BBS_GURVY" | ||
| ) | ||
|
|
||
| // curveAndTranslator maps a curve_id string (as stored in IdemixMSPConfig) to the corresponding | ||
| // math.Curve and dlog Translator. Returns an error for unknown curve IDs. | ||
| func curveAndTranslator(curveID string) (*math.Curve, idemixcrypto.Translator, error) { | ||
| switch curveID { | ||
| case curveIDFP256BN_AMCL: | ||
| c := math.Curves[math.FP256BN_AMCL] | ||
|
|
||
| return c, &amcl.Fp256bn{C: c}, nil | ||
| case curveIDBN254: | ||
| c := math.Curves[math.BN254] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| case curveIDFP256BN_AMCL_MIRACL: | ||
| c := math.Curves[math.FP256BN_AMCL_MIRACL] | ||
|
|
||
| return c, &amcl.Fp256bnMiracl{C: c}, nil | ||
| case curveIDBLS12_377_GURVY: | ||
| c := math.Curves[math.BLS12_377_GURVY] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| case curveIDBLS12_381_GURVY: | ||
| c := math.Curves[math.BLS12_381_GURVY] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| case curveIDBLS12_381: | ||
| c := math.Curves[math.BLS12_381] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| case curveIDBLS12_381_BBS: | ||
| c := math.Curves[math.BLS12_381_BBS] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| case curveIDBLS12_381_BBS_GURVY: | ||
| c := math.Curves[math.BLS12_381_BBS_GURVY] | ||
|
|
||
| return c, &amcl.Gurvy{C: c}, nil | ||
| default: | ||
| return nil, nil, fmt.Errorf("unknown curve id %q", curveID) | ||
| } | ||
| } | ||
|
|
||
| // Logger defines the logging interface required by Idemixmsp. | ||
| // This interface is compatible with the Go SDK log package and common logging facades. | ||
| type Logger interface { | ||
|
|
@@ -87,6 +141,8 @@ type Idemixmsp struct { | |
| revocationPK bccsp.Key | ||
| epoch int | ||
| logger Logger | ||
| aries bool | ||
| exportable bool | ||
| } | ||
|
|
||
| // defaultLogger is a simple logger implementation that wraps zap.SugaredLogger | ||
|
|
@@ -141,37 +197,42 @@ func (l *stdLogger) IsEnabledFor(level zapcore.Level) bool { | |
| return true // Standard logger always logs | ||
| } | ||
|
|
||
| // NewIdemixMsp creates a new instance of idemixmsp | ||
| // NewIdemixMsp creates a new instance of idemixmsp using the dlog scheme. | ||
| // The curve is determined at Setup time from IdemixMSPConfig.CurveId (default: FP256BN_AMCL). | ||
| func NewIdemixMsp(version MSPVersion) (MSP, error) { | ||
| logger := newDefaultLogger("idemix") | ||
| logger.Debugf("Creating Idemix-based MSP instance") | ||
| return NewIdemixMspWithLogger(version, newDefaultLogger("idemix")) | ||
| } | ||
|
|
||
| curve := math.Curves[math.FP256BN_AMCL] | ||
| csp, err := idemix.New(&keystore.Dummy{}, curve, &amcl.Fp256bn{C: curve}, true) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("unexpected condition, error received [%s]", err)) | ||
| // NewIdemixMspWithLogger creates a new instance of idemixmsp using the dlog scheme with a custom logger. | ||
| // The curve is determined at Setup time from IdemixMSPConfig.CurveId (default: FP256BN_AMCL). | ||
| // If logger is nil, the default logger is used. | ||
| func NewIdemixMspWithLogger(version MSPVersion, logger Logger) (MSP, error) { | ||
| if logger == nil { | ||
| logger = newDefaultLogger("idemix") | ||
| } | ||
|
|
||
| msp := Idemixmsp{csp: csp, logger: logger} | ||
| msp.version = version | ||
| logger.Debugf("Creating Idemix-based MSP instance") | ||
| msp := Idemixmsp{logger: logger, version: version, aries: false, exportable: true} | ||
|
|
||
| return &msp, nil | ||
| } | ||
|
|
||
| // NewIdemixMspAries creates a new | ||
| // instance of idemixmsp | ||
| // NewIdemixMspAries creates a new instance of idemixmsp using the Aries/BBS+ scheme. | ||
| // The curve is determined at Setup time from IdemixMSPConfig.CurveId; only BLS12_381_BBS | ||
| // and BLS12_381_BBS_GURVY are accepted (default: BLS12_381_BBS). | ||
| func NewIdemixMspAries(version MSPVersion) (MSP, error) { | ||
| logger := newDefaultLogger("idemix") | ||
| logger.Debugf("Creating Idemix-based MSP instance") | ||
| return NewIdemixMspAriesWithLogger(version, newDefaultLogger("idemix")) | ||
| } | ||
|
|
||
| curve := math.Curves[math.BLS12_381_BBS] | ||
| csp, err := idemix.NewAries(&keystore.Dummy{}, curve, &amcl.Gurvy{C: curve}, true) | ||
| if err != nil { | ||
| panic(fmt.Sprintf("unexpected condition, error received [%s]", err)) | ||
| // NewIdemixMspAriesWithLogger creates a new instance of idemixmsp using the Aries/BBS+ scheme with a custom logger. | ||
| // The curve is determined at Setup time from IdemixMSPConfig.CurveId; only BLS12_381_BBS | ||
| // and BLS12_381_BBS_GURVY are accepted (default: BLS12_381_BBS). | ||
| // If logger is nil, the default logger is used. | ||
| func NewIdemixMspAriesWithLogger(version MSPVersion, logger Logger) (MSP, error) { | ||
| if logger == nil { | ||
| logger = newDefaultLogger("idemix") | ||
| } | ||
|
|
||
| msp := Idemixmsp{csp: csp, logger: logger} | ||
| msp.version = version | ||
| logger.Debugf("Creating Idemix-based MSP instance") | ||
| msp := Idemixmsp{logger: logger, version: version, aries: true, exportable: true} | ||
|
|
||
| return &msp, nil | ||
| } | ||
|
|
@@ -192,11 +253,47 @@ func (msp *Idemixmsp) Setup(conf1 *m.MSPConfig) error { | |
| msp.name = conf.Name | ||
| msp.logger.Debugf("Setting up Idemix MSP instance %s", msp.name) | ||
|
|
||
| switch conf1.Type { | ||
| case int32(IDEMIX): | ||
| case int32(IDEMIX_ARIES): | ||
| default: | ||
| return errors.New("setup error: config is not of type IDEMIX") | ||
| // Enforce that the config type matches the constructor used. | ||
| if msp.aries { | ||
| if conf1.Type != int32(IDEMIX_ARIES) { | ||
| return fmt.Errorf("setup error: aries MSP requires config of type IDEMIX_ARIES, got %d", conf1.Type) | ||
| } | ||
| } else { | ||
| if conf1.Type != int32(IDEMIX) { | ||
| return fmt.Errorf("setup error: dlog MSP requires config of type IDEMIX, got %d", conf1.Type) | ||
| } | ||
| } | ||
|
|
||
| // Determine the curve from config.CurveId. | ||
| curveID := conf.CurveId | ||
| if msp.aries { | ||
| switch curveID { | ||
| case "", curveIDBLS12_381_BBS: | ||
| curveID = curveIDBLS12_381_BBS | ||
| case curveIDBLS12_381_BBS_GURVY: | ||
| // accepted | ||
| default: | ||
| return fmt.Errorf("setup error: aries MSP requires a BBS curve, got %q", curveID) | ||
| } | ||
|
Comment on lines
+269
to
+277
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We only support these 2?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you explicitly called NewIdemixMspAries, then we enforce this because the constructor was enforcing that curve |
||
| } else { | ||
| if curveID == "" { | ||
| curveID = curveIDFP256BN_AMCL | ||
| } | ||
| } | ||
|
|
||
| curve, tr, err := curveAndTranslator(curveID) | ||
| if err != nil { | ||
| return fmt.Errorf("setup error: %w", err) | ||
| } | ||
|
|
||
| // Build the BCCSP using the curve selected from config. | ||
| if msp.aries { | ||
| msp.csp, err = idemix.NewAries(&keystore.Dummy{}, curve, tr, msp.exportable) | ||
| } else { | ||
| msp.csp, err = idemix.New(&keystore.Dummy{}, curve, tr, msp.exportable) | ||
| } | ||
| if err != nil { | ||
| return fmt.Errorf("setup error: failed to create BCCSP: %w", err) | ||
| } | ||
|
|
||
| // Import Issuer Public Key | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this expected? We have CLAUDE.md pointing to @AGENTS.md, and AGENTS.md whose first line is CLAUDE.md?