Skip to content

Commit 657ef1b

Browse files
author
Christian
committed
feat: add derivePassedFromEstimators to compute top-level pass/fail
- Introduce `derivePassedFromEstimators` function to determine the overall `Passed` status by aggregating results from IID and Non-IID estimators. - Update gRPC server logic to use `derivePassedFromEstimators` for response construction. - Add comprehensive unit tests to validate all scenarios of `derivePassedFromEstimators`.
1 parent 5e086ec commit 657ef1b

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package service
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
pb "github.com/AmmannChristian/nist-800-90b/pkg/pb"
9+
)
10+
11+
func TestDerivePassedFromEstimators(t *testing.T) {
12+
passed := func(name string) *pb.Sp80090BEstimatorResult {
13+
return &pb.Sp80090BEstimatorResult{Name: name, Passed: true}
14+
}
15+
failed := func(name string) *pb.Sp80090BEstimatorResult {
16+
return &pb.Sp80090BEstimatorResult{Name: name, Passed: false}
17+
}
18+
19+
tests := []struct {
20+
name string
21+
iid []*pb.Sp80090BEstimatorResult
22+
nonIID []*pb.Sp80090BEstimatorResult
23+
expectAll bool
24+
}{
25+
{
26+
name: "all passed",
27+
iid: []*pb.Sp80090BEstimatorResult{passed("MCV"), passed("Chi2")},
28+
nonIID: []*pb.Sp80090BEstimatorResult{passed("MCV"), passed("Collision")},
29+
expectAll: true,
30+
},
31+
{
32+
name: "iid failure propagates",
33+
iid: []*pb.Sp80090BEstimatorResult{passed("MCV"), failed("Chi2")},
34+
nonIID: []*pb.Sp80090BEstimatorResult{passed("MCV")},
35+
expectAll: false,
36+
},
37+
{
38+
name: "non-iid failure propagates",
39+
iid: []*pb.Sp80090BEstimatorResult{passed("MCV")},
40+
nonIID: []*pb.Sp80090BEstimatorResult{passed("MCV"), failed("Collision")},
41+
expectAll: false,
42+
},
43+
{
44+
name: "empty results returns true",
45+
iid: nil,
46+
nonIID: nil,
47+
expectAll: true,
48+
},
49+
{
50+
name: "only iid with failure",
51+
iid: []*pb.Sp80090BEstimatorResult{failed("MCV")},
52+
nonIID: nil,
53+
expectAll: false,
54+
},
55+
{
56+
name: "only non-iid all passed",
57+
iid: nil,
58+
nonIID: []*pb.Sp80090BEstimatorResult{passed("MCV"), passed("Collision")},
59+
expectAll: true,
60+
},
61+
}
62+
63+
for _, tt := range tests {
64+
t.Run(tt.name, func(t *testing.T) {
65+
result := derivePassedFromEstimators(tt.iid, tt.nonIID)
66+
assert.Equal(t, tt.expectAll, result)
67+
})
68+
}
69+
}

internal/service/grpc_server.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (s *GRPCServer) AssessEntropy(ctx context.Context, req *pb.Sp80090BAssessme
134134
MinEntropy: minEntropy,
135135
IidResults: iidResults,
136136
NonIidResults: nonIIDResults,
137-
Passed: true,
137+
Passed: derivePassedFromEstimators(iidResults, nonIIDResults),
138138
AssessmentSummary: "NIST SP 800-90B entropy assessment completed",
139139
SampleCount: uint64(len(req.Data)),
140140
BitsPerSymbol: usedBits,
@@ -151,6 +151,23 @@ func (s *GRPCServer) AssessEntropy(ctx context.Context, req *pb.Sp80090BAssessme
151151
return response, nil
152152
}
153153

154+
// derivePassedFromEstimators computes the top-level Passed flag by ANDing
155+
// all individual estimator Passed fields across IID and Non-IID results.
156+
// SP 800-90B does not define a top-level pass/fail — this is product-defined.
157+
func derivePassedFromEstimators(iidResults, nonIIDResults []*pb.Sp80090BEstimatorResult) bool {
158+
for _, r := range iidResults {
159+
if !r.Passed {
160+
return false
161+
}
162+
}
163+
for _, r := range nonIIDResults {
164+
if !r.Passed {
165+
return false
166+
}
167+
}
168+
return true
169+
}
170+
154171
// convertEstimatorsToProto maps internal EstimatorResult values to their
155172
// protobuf representation. Entropy estimators include the estimate in the
156173
// details map; statistical tests (where the estimate is not valid) are

0 commit comments

Comments
 (0)