Skip to content

Commit 05abf63

Browse files
committed
Merge branch 'main' of github.com:ounsworth/merkle-tree-certs
2 parents da1b60d + 1406ee1 commit 05abf63

7 files changed

Lines changed: 126 additions & 74 deletions

File tree

demo/config.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
VersionPlants01
2525
VersionPlants02
2626
VersionPlants04
27+
VersionPlants05
2728
)
2829

2930
func (v DraftVersion) String() string {
@@ -38,6 +39,8 @@ func (v DraftVersion) String() string {
3839
return "plants-02"
3940
case VersionPlants04:
4041
return "plants-04"
42+
case VersionPlants05:
43+
return "plants-05"
4144
}
4245
panic(fmt.Sprintf("unknown version %d", v))
4346
}
@@ -67,6 +70,8 @@ func DraftVersionFromString(s string) (v DraftVersion, ok bool) {
6770
return VersionPlants02, true
6871
case "plants-04":
6972
return VersionPlants04, true
73+
case "plants-05":
74+
return VersionPlants05, true
7075

7176
default:
7277
return 0, false
@@ -150,9 +155,14 @@ type CosignerConfig struct {
150155
PrivateKey []byte
151156
}
152157

158+
type SerialConfig struct {
159+
Log uint16
160+
Index uint64
161+
}
162+
153163
type CACertConfig struct {
154164
CertConfigBase
155-
MinSerial uint64
165+
MinSerial, MaxSerial SerialConfig
156166
}
157167

158168
type CertConfigBase struct {

demo/encode.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ func addSubject(b *cryptobyte.Builder, entry *EntryConfig) {
128128
}
129129

130130
type mtcCAInfo struct {
131+
version DraftVersion
131132
cosigner *Cosigner
132133
minSerial uint64
134+
maxSerial uint64
133135
}
134136

135137
func addExtensions(b *cryptobyte.Builder, config *CertConfigBase, mtcCA *mtcCAInfo) {
@@ -242,6 +244,9 @@ func addExtensions(b *cryptobyte.Builder, config *CertConfigBase, mtcCA *mtcCAIn
242244
}
243245
})
244246
seq.AddASN1Uint64(mtcCA.minSerial)
247+
if mtcCA.version >= VersionPlants05 {
248+
seq.AddASN1Uint64(mtcCA.maxSerial)
249+
}
245250
})
246251
})
247252
})
@@ -423,6 +428,15 @@ func CreateCACertificate(config *CAConfig, cosigner *Cosigner) ([]byte, error) {
423428
return nil, err
424429
}
425430

431+
if config.CACert.MinSerial.Index >= 1<<48 {
432+
return nil, fmt.Errorf("invalid MinSerial index")
433+
}
434+
if config.CACert.MaxSerial.Index >= 1<<48 {
435+
return nil, fmt.Errorf("invalid MaxSerial index")
436+
}
437+
minSerial := (uint64(config.CACert.MinSerial.Log) << 48) | config.CACert.MinSerial.Index
438+
maxSerial := (uint64(config.CACert.MaxSerial.Log) << 48) | config.CACert.MaxSerial.Index
439+
426440
b := cryptobyte.NewBuilder(nil)
427441
b.AddASN1(cbasn1.SEQUENCE, func(cert *cryptobyte.Builder) {
428442
cert.AddASN1(cbasn1.SEQUENCE, func(tbs *cryptobyte.Builder) {
@@ -433,9 +447,12 @@ func CreateCACertificate(config *CAConfig, cosigner *Cosigner) ([]byte, error) {
433447
addValidity(tbs, &config.CACert.CertConfigBase)
434448
addX509Name(tbs, config.ID) // Subject
435449
tbs.AddBytes(spki)
450+
436451
addExtensions(tbs, &config.CACert.CertConfigBase, &mtcCAInfo{
452+
version: config.Version,
437453
cosigner: cosigner,
438-
minSerial: config.CACert.MinSerial,
454+
minSerial: minSerial,
455+
maxSerial: maxSerial,
439456
})
440457
})
441458
addUnsignedSigAlg(cert)

demo/log.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ const HashSize = sha256.Size
1010

1111
type HashValue = [HashSize]byte
1212

13+
func HashEmpty() HashValue {
14+
h := sha256.New()
15+
var ret HashValue
16+
h.Sum(ret[:0])
17+
return ret
18+
}
19+
1320
func HashLeaf(b []byte) HashValue {
1421
h := sha256.New()
1522
h.Write([]byte{0})
@@ -30,9 +37,12 @@ func HashNode(left, right *HashValue) HashValue {
3037
}
3138

3239
func IsValidSubtree(start, end int) bool {
33-
if 0 > start || start >= end {
40+
if 0 > start || start > end {
3441
return false
3542
}
43+
if start == end {
44+
return true
45+
}
3646
ceil := uint(1) << (bits.UintSize - bits.LeadingZeros(uint(end-start-1)))
3747
return uint(start)&(ceil-1) == 0
3848
}
@@ -74,6 +84,9 @@ func (mt *MerkleTree) SubtreeHash(start, end int) (HashValue, error) {
7484
if end > mt.Size() {
7585
return HashValue{}, fmt.Errorf("subtree [%d, %d) contains more elements than tree of size %d", start, end, mt.Size())
7686
}
87+
if start == end {
88+
return HashEmpty(), nil
89+
}
7790
// Start at the largest complete subtree on the right edge.
7891
last := end - 1
7992
level := bits.TrailingZeros(^uint(last - start))
@@ -138,6 +151,9 @@ func (mt *MerkleTree) SubtreeConsistencyProof(start, end, n int) ([]byte, error)
138151
if n > mt.Size() {
139152
return nil, fmt.Errorf("tree of size %d is larger than the Merkle Tree of size %d", n, mt.Size())
140153
}
154+
if start == end {
155+
return nil, nil
156+
}
141157
return mt.subtreeSubproof(start, end, 0, n, true)
142158
}
143159

@@ -193,14 +209,14 @@ func (mt *MerkleTree) subtreeSubproof(start, end, lo, hi int, known bool) ([]byt
193209
}
194210

195211
func SubtreesForInterval(start, end int) (start1, end1, start2, end2 int, err error) {
196-
if 0 > start || start >= end {
212+
if 0 > start || start > end {
197213
err = fmt.Errorf("invalid interval [%d, %d)", start, end)
198214
return
199215
}
200-
if end-start == 1 {
216+
if end-start <= 1 {
201217
start1 = start
202-
start2 = start
203218
end1 = end
219+
start2 = end
204220
end2 = end
205221
return
206222
}

demo/log_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ func TestSubtreesForInterval(t *testing.T) {
8888
start1, end1 int
8989
start2, end2 int
9090
}{
91-
{start: 8, end: 9, start1: 8, end1: 9, start2: 8, end2: 9},
91+
{start: 9, end: 9, start1: 9, end1: 9, start2: 9, end2: 9},
92+
{start: 8, end: 9, start1: 8, end1: 9, start2: 9, end2: 9},
9293
{start: 5, end: 13, start1: 4, end1: 8, start2: 8, end2: 13},
9394
{start: 7, end: 9, start1: 7, end1: 8, start2: 8, end2: 9},
9495
}

demo/mtc.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"Version": "plants-04",
2+
"Version": "plants-05",
33
"ID": "32473.1",
44
"LogNumber": 1,
55
"Cosigners": [
@@ -28,7 +28,9 @@
2828
"NotBefore": "2020-01-01T00:00:00Z",
2929
"NotAfter": "2030-12-31T23:59:59Z",
3030
"IsCA": true,
31-
"KeyUsage": ["CertSign"]
31+
"KeyUsage": ["CertSign"],
32+
"MinSerial": {"Log": 1, "Index": 0},
33+
"MaxSerial": {"Log": 5, "Index": 281474976710655}
3234
},
3335
"Entries": [
3436
{

demo/vectors_test.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ func writeProofLine(w io.Writer, prefix string, proof []byte) {
3838
func TestSubtreeHashVectors(t *testing.T) {
3939
tree := subtreeVectorTree()
4040
h := sha256.New()
41-
for end := 1; end <= subtreeVectorMax; end++ {
42-
for start := 0; start < end; start++ {
41+
for end := 0; end <= subtreeVectorMax; end++ {
42+
for start := 0; start <= end; start++ {
4343
if !IsValidSubtree(start, end) {
4444
continue
4545
}
@@ -50,7 +50,7 @@ func TestSubtreeHashVectors(t *testing.T) {
5050
fmt.Fprintf(h, "[%d, %d) %x\n", start, end, subtreeHash[:])
5151
}
5252
}
53-
const want = "94a95384a8c69acea9b50d035a58285b3a777cb7a724005faa5e1f1e1190007f"
53+
const want = "b82806ad4265bb151c1119c0f4db437bb4d1a1f887b3a7fba1cd4ebf552e3e81"
5454
if got := fmt.Sprintf("%x", h.Sum(nil)); got != want {
5555
t.Errorf("subtree hash vector = %s, want %s", got, want)
5656
}
@@ -59,8 +59,8 @@ func TestSubtreeHashVectors(t *testing.T) {
5959
func TestSubtreeInclusionProofVectors(t *testing.T) {
6060
tree := subtreeVectorTree()
6161
h := sha256.New()
62-
for end := 1; end <= subtreeVectorMax; end++ {
63-
for start := 0; start < end; start++ {
62+
for end := 0; end <= subtreeVectorMax; end++ {
63+
for start := 0; start <= end; start++ {
6464
if !IsValidSubtree(start, end) {
6565
continue
6666
}
@@ -83,8 +83,8 @@ func TestSubtreeConsistencyProofVectors(t *testing.T) {
8383
tree := subtreeVectorTree()
8484
h := sha256.New()
8585
for n := 0; n <= subtreeVectorMax; n++ {
86-
for end := 1; end <= n; end++ {
87-
for start := 0; start < end; start++ {
86+
for end := 0; end <= n; end++ {
87+
for start := 0; start <= end; start++ {
8888
if !IsValidSubtree(start, end) {
8989
continue
9090
}
@@ -96,28 +96,24 @@ func TestSubtreeConsistencyProofVectors(t *testing.T) {
9696
}
9797
}
9898
}
99-
const want = "c586ebbb73a5621baf2140095d87dde934e3b6503a562a1a5215b8209edd083d"
99+
const want = "10fa99b37bf9bf9ffa26b412fbd98bd75363256d0b75d61bc4538b9c9c5a0a74"
100100
if got := fmt.Sprintf("%x", h.Sum(nil)); got != want {
101101
t.Errorf("subtree consistency proof vector = %s, want %s", got, want)
102102
}
103103
}
104104

105105
func TestEfficientCoveringSubtreeVectors(t *testing.T) {
106106
h := sha256.New()
107-
for end := 1; end <= subtreeVectorMax; end++ {
108-
for start := 0; start < end; start++ {
109-
if IsValidSubtree(start, end) {
110-
fmt.Fprintf(h, "[%d, %d)\n", start, end)
111-
continue
112-
}
107+
for end := 0; end <= subtreeVectorMax; end++ {
108+
for start := 0; start <= end; start++ {
113109
start1, end1, start2, end2, err := SubtreesForInterval(start, end)
114110
if err != nil {
115111
t.Fatalf("SubtreesForInterval(%d, %d): %v", start, end, err)
116112
}
117113
fmt.Fprintf(h, "[%d, %d) [%d, %d)\n", start1, end1, start2, end2)
118114
}
119115
}
120-
const want = "e0aecb912a10c57d753b6ecc64db73217f9bc4ed10fcb4e9062be3b6fbe1ebfd"
116+
const want = "7fd9c8b926e9d2b5cf831560e8ce295a5ef97ad5c5ede4ea0dea28a8c8fc8bb0"
121117
if got := fmt.Sprintf("%x", h.Sum(nil)); got != want {
122118
t.Errorf("efficient covering subtree vector = %s, want %s", got, want)
123119
}

0 commit comments

Comments
 (0)