an atproto pds written in F# (.NET 9) 馃
pds
fsharp
giraffe
dotnet
atproto
1锘縨odule Tests
2
3open Xunit
4open PDSharp.Core.Models
5open PDSharp.Core.Config
6open PDSharp.Core.Crypto
7open PDSharp.Core
8open PDSharp.Core.DidResolver
9open Org.BouncyCastle.Utilities.Encoders
10open System.Text
11open System.Text.Json
12open Org.BouncyCastle.Math
13
14[<Fact>]
15let ``Can instantiate AppConfig`` () =
16 let config = {
17 PublicUrl = "https://example.com"
18 DidHost = "did:web:example.com"
19 }
20
21 Assert.Equal("did:web:example.com", config.DidHost)
22
23[<Fact>]
24let ``CID TryParse roundtrip`` () =
25 let hash = Crypto.sha256Str "test-data"
26 let cid = Cid.FromHash hash
27 let cidStr = cid.ToString()
28
29 match Cid.TryParse cidStr with
30 | Some parsed -> Assert.Equal<byte[]>(cid.Bytes, parsed.Bytes)
31 | None -> Assert.Fail "TryParse should succeed for valid CID"
32
33[<Fact>]
34let ``CID TryParse returns None for invalid`` () =
35 Assert.True(Cid.TryParse("invalid").IsNone)
36 Assert.True(Cid.TryParse("").IsNone)
37 Assert.True(Cid.TryParse("btooshort").IsNone)
38
39[<Fact>]
40let ``Can instantiate DescribeServerResponse`` () =
41 let response = {
42 availableUserDomains = [ "example.com" ]
43 did = "did:web:example.com"
44 inviteCodeRequired = true
45 }
46
47 Assert.Equal("did:web:example.com", response.did)
48 Assert.Equal(1, response.availableUserDomains.Length)
49
50[<Fact>]
51let ``SHA-256 Hashing correct`` () =
52 let input = "hello world"
53 let hash = sha256Str input
54 let expected = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
55 let actual = Hex.ToHexString(hash)
56 Assert.Equal(expected, actual)
57
58[<Fact>]
59let ``ECDSA P-256 Sign and Verify`` () =
60 let keyPair = generateKey P256
61 let data = Encoding.UTF8.GetBytes("test message")
62 let hash = sha256 data
63
64 let signature = sign keyPair hash
65 Assert.True(signature.Length = 64, "Signature should be 64 bytes (R|S)")
66
67 let valid = verify keyPair hash signature
68 Assert.True(valid, "Signature verification failed")
69
70[<Fact>]
71let ``ECDSA K-256 Sign and Verify`` () =
72 let keyPair = generateKey K256
73 let data = Encoding.UTF8.GetBytes("test k256")
74 let hash = sha256 data
75
76 let signature = sign keyPair hash
77 Assert.True(signature.Length = 64, "Signature should be 64 bytes")
78
79 let valid = verify keyPair hash signature
80 Assert.True(valid, "Signature verification failed")
81
82[<Fact>]
83let ``Low-S Enforcement Logic`` () =
84 let n =
85 BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) // secp256k1 N
86
87 let halfN = n.ShiftRight(1)
88 let highS = halfN.Add(BigInteger.One)
89
90 let lowS = enforceLowS highS n
91 Assert.True(lowS.CompareTo halfN <= 0, "S value should be <= N/2")
92 Assert.Equal(n.Subtract highS, lowS)
93
94[<Fact>]
95let ``DidDocument JSON deserialization`` () =
96 let json =
97 """{
98 "id": "did:web:example.com",
99 "verificationMethod": [{
100 "id": "did:web:example.com#atproto",
101 "type": "Multikey",
102 "controller": "did:web:example.com",
103 "publicKeyMultibase": "zQ3sh..."
104 }]
105 }"""
106
107 let doc =
108 JsonSerializer.Deserialize<DidDocument>(json, JsonSerializerOptions(PropertyNameCaseInsensitive = true))
109
110 Assert.Equal("did:web:example.com", doc.Id)
111 Assert.Single doc.VerificationMethod |> ignore
112 Assert.Equal("Multikey", doc.VerificationMethod.Head.Type)
113
114[<Fact>]
115let ``CID Generation from Hash`` () =
116 let hash =
117 Hex.Decode("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")
118
119 let cid = Cid.FromHash hash
120 Assert.Equal<byte>(0x01uy, cid.Bytes.[0])
121 Assert.Equal<byte>(0x71uy, cid.Bytes.[1])
122 Assert.Equal<byte>(0x12uy, cid.Bytes.[2])
123 Assert.Equal<byte>(0x20uy, cid.Bytes.[3])
124
125[<Fact>]
126let ``DAG-CBOR Canonical Sorting`` () =
127 let m = Map.ofList [ ("b", box 1); ("a", box 2) ]
128 let encoded = DagCbor.encode m
129 let hex = Hex.ToHexString encoded
130 Assert.Equal("a2616102616201", hex)
131
132[<Fact>]
133let ``DAG-CBOR Sorting Length vs Bytes`` () =
134 let m = Map.ofList [ ("aa", box 1); ("b", box 2) ]
135 let encoded = DagCbor.encode m
136 let hex = Hex.ToHexString encoded
137 Assert.Equal("a261620262616101", hex)