Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
package drand_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
datekeys "g.activething.com/go/DateKeys"
|
|
|
|
|
"g.activething.com/go/DateKeys/internal/testkit"
|
|
|
|
|
"g.activething.com/go/DateKeys/profile"
|
|
|
|
|
"g.activething.com/go/DateKeys/provider"
|
|
|
|
|
"g.activething.com/go/DateKeys/provider/drand"
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var sig1000 = hex.EncodeToString(testkit.Release(1000).Signature)
|
|
|
|
|
|
|
|
|
|
func serve(t *testing.T, h http.HandlerFunc) string {
|
|
|
|
|
t.Helper()
|
|
|
|
|
s := httptest.NewServer(h)
|
|
|
|
|
t.Cleanup(s.Close)
|
|
|
|
|
return s.URL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRaceWaitsForAValidSignature(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
bad := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Fprintf(w, `{"round":1000,"signature":"%s"}`, strings.Repeat("0", 96))
|
|
|
|
|
})
|
|
|
|
|
good := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if r.URL.Path != "/v2/chains/"+p.ChainHashHex()+"/rounds/1000" {
|
|
|
|
|
t.Errorf("request not pinned to the chain: %s", r.URL.Path)
|
|
|
|
|
}
|
|
|
|
|
time.Sleep(25 * time.Millisecond)
|
|
|
|
|
fmt.Fprintf(w, `{"round":1000,"signature":"%s"}`, sig1000)
|
|
|
|
|
})
|
|
|
|
|
c := drand.NewWithHTTPClient(http.DefaultClient, bad, good)
|
|
|
|
|
rel, err := c.Fetch(context.Background(), p, provider.Condition{Round: 1000})
|
|
|
|
|
if err != nil || hex.EncodeToString(rel.Signature) != sig1000 || rel.Round != 1000 {
|
|
|
|
|
t.Fatalf("race failed: %+v %v", rel, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRejectMalformedRelayResponses(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
for _, payload := range []string{
|
|
|
|
|
`{"round":999,"signature":"` + sig1000 + `"}`,
|
|
|
|
|
`{"round":1000,"signature":"` + sig1000 + `","randomness":"fake"}`,
|
|
|
|
|
`{"round":1000,"signature":"fake"}`,
|
|
|
|
|
`{"round":1000,"signature":"` + sig1000 + `"} {}`,
|
|
|
|
|
`{"round":1000,"signature":"` + hex.EncodeToString(testkit.Release(1001).Signature) + `"}`,
|
|
|
|
|
strings.Repeat("x", 9000),
|
|
|
|
|
``,
|
|
|
|
|
} {
|
|
|
|
|
url := serve(t, func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, payload) })
|
|
|
|
|
c := drand.NewWithHTTPClient(http.DefaultClient, url)
|
|
|
|
|
_, err := c.Fetch(context.Background(), p, provider.Condition{Round: 1000})
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
if !onlyUnavailable(err) {
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
t.Errorf("accepted or misclassified %.40q: %v", payload, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
// onlyUnavailable reports whether err wraps ErrReleaseUnavailable and no
|
|
|
|
|
// other normative error: every error of this module wraps exactly one.
|
|
|
|
|
func onlyUnavailable(err error) bool {
|
|
|
|
|
for _, e := range datekeys.All() {
|
|
|
|
|
if errors.Is(err, e) != (e == datekeys.ErrReleaseUnavailable) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Spec §63 step 9: when no relay returns a valid release, the only code of
|
|
|
|
|
// the error of Fetch is ErrReleaseUnavailable, although a relay's answer
|
|
|
|
|
// breaks a rule of step 10, whose code its failure carries: a release of
|
|
|
|
|
// another round, signed for that round, or a negated signature. The failure
|
|
|
|
|
// of each relay stays in the text.
|
|
|
|
|
func TestFetchErrorHasOneCode(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
other := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Fprintf(w, `{"round":1001,"signature":"%s"}`, hex.EncodeToString(testkit.Release(1001).Signature))
|
|
|
|
|
})
|
|
|
|
|
negated := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Fprintf(w, `{"round":1000,"signature":"%s"}`, hex.EncodeToString(testkit.Negated(testkit.Release(1000).Signature)))
|
|
|
|
|
})
|
|
|
|
|
reason := map[string]string{
|
|
|
|
|
other: "release for round 1001, expected 1000: ERR_ROUND_MISMATCH",
|
|
|
|
|
negated: "does not verify as the BLS signature of round 1000",
|
|
|
|
|
}
|
|
|
|
|
for _, relays := range [][]string{{other}, {other, negated}} {
|
|
|
|
|
_, err := drand.NewWithHTTPClient(http.DefaultClient, relays...).Fetch(context.Background(), p, provider.Condition{Round: 1000})
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Fatalf("%d relays: a release was accepted", len(relays))
|
|
|
|
|
}
|
|
|
|
|
if !onlyUnavailable(err) || datekeys.Code(err) != "ERR_RELEASE_UNAVAILABLE" {
|
|
|
|
|
t.Errorf("%d relays: %v wraps another normative error", len(relays), err)
|
|
|
|
|
}
|
|
|
|
|
for _, relay := range relays {
|
|
|
|
|
if !strings.Contains(err.Error(), relay+": provider: ") || !strings.Contains(err.Error(), reason[relay]) {
|
|
|
|
|
t.Errorf("%d relays: the failure of %s is not in %q", len(relays), relay, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
func TestRandomnessMustMatchWhenPresent(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
sum := "e1f1cb5a9ddd0e2ae4a4a8c5bf42e8e1e1ed8b5a9f1f7da1a3f1d2bb0f1b2c3d"
|
|
|
|
|
url := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Fprintf(w, `{"round":1000,"signature":"%s","randomness":"%s"}`, sig1000, sum)
|
|
|
|
|
})
|
|
|
|
|
_, err := drand.NewWithHTTPClient(http.DefaultClient, url).Fetch(context.Background(), p, provider.Condition{Round: 1000})
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
if !onlyUnavailable(err) || !strings.Contains(err.Error(), "randomness does not match the signature") {
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
t.Fatalf("wrong randomness accepted: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestUnavailabilityAndCancellation(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
for _, status := range []int{404, 425, 503} {
|
|
|
|
|
url := serve(t, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(status) })
|
|
|
|
|
_, err := drand.NewWithHTTPClient(http.DefaultClient, url).Fetch(context.Background(), p, provider.Condition{Round: 1000})
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
if !onlyUnavailable(err) {
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
t.Fatalf("HTTP %d: %v", status, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
// A context that ends before the request, or during it, stays
|
|
|
|
|
// detectable, whether Fetch sees it end before the relay fails because
|
|
|
|
|
// of it or after.
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
url := serve(t, func(w http.ResponseWriter, r *http.Request) { time.Sleep(time.Second) })
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
cancel()
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
if _, err := drand.NewWithHTTPClient(http.DefaultClient, url).Fetch(ctx, p, provider.Condition{Round: 1000}); !onlyUnavailable(err) || !errors.Is(err, context.Canceled) {
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
t.Fatalf("ignored cancellation: %v", err)
|
|
|
|
|
}
|
Spec v0.8.2: second-round corrections from the formal review
The second round of the formal review confirmed the nine corrections of
c57ed48 and asked for these, recorded in §76 as corrections 4 to 6 and
an editorial note:
- §72: an encoder MUST NOT write a registered extension in an object or
array it is not registered for; §54: a reader MUST NOT interpret the
data of a noncritical one it ignores for that reason. capsule.Encrypt
and accesskey.Encode take no Registry, so the application applies the
rule; their documentation and extension.Placement say so.
- §17 and §51 give the step-10 codes only for a directly supplied
release, as step 10 does; a network source discards a failing one at
step 9.
- Step 9 reports ERR_RELEASE_UNAVAILABLE and no other code, whatever the
failure of the source. provider/drand.Client keeps each relay's failure
as text only (errors.Join made a relay's ERR_ROUND_MISMATCH match with
errors.Is), and capsule.Open keeps only the text of a source error that
carries another code (a caller's source failing with
ERR_RELEASE_INVALID gave that code at step 9). A context that ended
stays detectable: Fetch now has a single failure path, so the canceled
and deadline cases are deterministic.
- TestExtensionPlacement covers the noncritical array of a .dkk: with
the object-blind extension.CheckNoncritical at step 9.a it fails.
- Editorial: §28.1 "analizan solo la cabecera age", one arrow at step 9,
two §76 introductions; §73 lines for release sources and placement.
- testdata/README.md says the corpus registers its extensions in both
arrays of every object; traceability, CHANGELOG and both READMEs
(integrity holds against whoever lacks the file keys, §27, §55.1)
follow. Spec dated 28 September 2026; new SHA-256 in spec/README.md.
No fixture or vector changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
|
|
|
ctx, cancel = context.WithTimeout(context.Background(), 20*time.Millisecond)
|
|
|
|
|
defer cancel()
|
|
|
|
|
if _, err := drand.NewWithHTTPClient(http.DefaultClient, url).Fetch(ctx, p, provider.Condition{Round: 1000}); !onlyUnavailable(err) || !errors.Is(err, context.DeadlineExceeded) {
|
|
|
|
|
t.Fatalf("ignored the deadline: %v", err)
|
|
|
|
|
}
|
Initial implementation of the DateKeys Protocol v0.8.1
Reference implementation in Go, built from the implementation plan
(milestones M0 to M5): datekey, profile, provider, codec, agewrap,
extension, capsule, accesskey, the datekeys CLI, official vectors and
fixtures, the mutation corpus, fuzz targets, interop and live tests,
CI workflows, traceability and policy documents.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 weeks ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRedirectsAreNotFollowed(t *testing.T) {
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
target := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
fmt.Fprintf(w, `{"round":1000,"signature":"%s"}`, sig1000)
|
|
|
|
|
})
|
|
|
|
|
redirect := serve(t, func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Redirect(w, r, target+r.URL.Path, http.StatusFound)
|
|
|
|
|
})
|
|
|
|
|
if _, err := drand.New(redirect).Fetch(context.Background(), p, provider.Condition{Round: 1000}); err == nil {
|
|
|
|
|
t.Fatal("followed a redirect")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInvalidRequests(t *testing.T) {
|
|
|
|
|
c := drand.New("http://127.0.0.1:1")
|
|
|
|
|
p := profile.Quicknet()
|
|
|
|
|
if _, err := c.Fetch(context.Background(), p, provider.Condition{Round: 0}); !errors.Is(err, datekeys.ErrDateKeyInvalid) {
|
|
|
|
|
t.Fatalf("round 0: %v", err)
|
|
|
|
|
}
|
|
|
|
|
other := profile.Quicknet()
|
|
|
|
|
other.Provider = "other"
|
|
|
|
|
if _, err := c.Fetch(context.Background(), other, provider.Condition{Round: 1}); !errors.Is(err, datekeys.ErrUnknownProfile) {
|
|
|
|
|
t.Fatalf("non-drand profile: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|