Skip to content

Commit 457d613

Browse files
author
Shota Jolbordi
committed
Add more tests
Signed-off-by: Shota Jolbordi <[email protected]>
1 parent b97c5af commit 457d613

File tree

1 file changed

+173
-8
lines changed

1 file changed

+173
-8
lines changed

src/test/scala/io/iohk/atala/prism/node/identity/PrismDidSpec.scala

+173-8
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,191 @@ import org.scalatest.matchers.must.Matchers.convertToAnyMustWrapper
44
import org.scalatest.wordspec.AnyWordSpec
55
import io.iohk.atala.prism.node.crypto.CryptoUtils.Sha256Hash
66
import io.iohk.atala.prism.node.utils.Base64Utils
7+
import io.iohk.atala.prism.node.crypto.{CryptoUtils, CryptoTestUtils}
8+
import io.iohk.atala.prism.protos.node_models._
9+
import org.scalatest.OptionValues._
710

811
class PrismDidSpec extends AnyWordSpec {
912

10-
"PrismDid library" should {
13+
val canonicalSuffixHex = "9b5118411248d9663b6ab15128fba8106511230ff654e7514cdcc4ce919bde9b"
14+
val canonicalSuffix = Sha256Hash.fromHex(canonicalSuffixHex)
15+
val encodedStateUsedBase64 =
16+
"Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VjcDI1NmsxEiEDHpf-yhIns-LP3tLvA8icC5FJ1ZlBwbllPtIdNZ3q0jU"
17+
val encodedStateUsed = Base64Utils.decodeURL(encodedStateUsedBase64)
18+
19+
val short = PrismDid.buildCanonical(canonicalSuffix)
20+
val long = PrismDid.buildLongForm(canonicalSuffix, encodedStateUsed)
21+
22+
private def createLongFormDidFromAtalaOperationUnsafely(atalaOperation: AtalaOperation): LongFormPrismDid = {
23+
val encodedState = atalaOperation.toByteArray
24+
val encodedStateBase64 = Base64Utils.encodeURL(encodedState)
25+
val stateHash = Sha256Hash.compute(encodedState)
1126

12-
val canonicalSuffixHex = "9b5118411248d9663b6ab15128fba8106511230ff654e7514cdcc4ce919bde9b"
13-
val canonicalSuffix = Sha256Hash.fromHex(canonicalSuffixHex)
14-
val encodedStateUsedBase64 =
15-
"Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VjcDI1NmsxEiEDHpf-yhIns-LP3tLvA8icC5FJ1ZlBwbllPtIdNZ3q0jU"
16-
val encodedStateUsed = Base64Utils.decodeURL(encodedStateUsedBase64)
27+
val methodSpecificId = DidMethodSpecificId.fromSections(Array(stateHash.hexEncoded, encodedStateBase64))
28+
val did = Did(PrismDid.PRISM_METHOD, methodSpecificId)
29+
LongFormPrismDid(did, stateHash, atalaOperation)
30+
}
1731

18-
val short = PrismDid.buildCanonical(canonicalSuffix)
19-
val long = PrismDid.buildLongForm(canonicalSuffix, encodedStateUsed)
32+
"PrismDid library" should {
2033

2134
// HASHING
2235
"asCanonical should work for long and short form dids" in {
2336
canonicalSuffixHex mustBe short.asCanonical().suffix
2437
canonicalSuffixHex mustBe long.asCanonical().suffix
2538
}
2639

40+
"values of canonical did should be a valid prism did with correct suffix" in {
41+
short.asCanonical().value mustBe s"did:prism:$canonicalSuffixHex"
42+
long.asCanonical().value mustBe s"did:prism:$canonicalSuffixHex"
43+
}
44+
45+
"obtain did suffix correctly" in {
46+
short.suffix mustBe canonicalSuffixHex
47+
long.suffix mustBe s"$canonicalSuffixHex:$encodedStateUsedBase64"
48+
}
49+
50+
"properly validate a long for DID" in {
51+
// bytes extracted from a randomly generated key
52+
val xBytes = Array[Byte](
53+
30, -105, -2, -54, 18, 39, -77, -30, -49, -34, -46, -17, 3, -56, -100, 11, -111, 73, -43, -103, 65, -63, -71,
54+
101, 62, -46, 29, 53, -99, -22, -46, 53
55+
)
56+
val yBytes = Array[Byte](
57+
-103, 81, -25, 85, 91, -109, -113, 111, 106, 7, -95, 3, 4, 36, 22, -11, -65, 126, -4, -116, -42, -90, -72, -118,
58+
87, -120, 17, -119, 23, -77, -118, 69
59+
)
60+
val masterKey = CryptoUtils.SecpPublicKey.unsafeFromByteCoordinates(xBytes, yBytes)
61+
62+
val expectedInitialState =
63+
AtalaOperation(
64+
operation = AtalaOperation.Operation.CreateDid(
65+
CreateDIDOperation(
66+
didData = Some(
67+
CreateDIDOperation.DIDCreationData(
68+
publicKeys = List(
69+
PublicKey(
70+
id = PrismDid.DEFAULT_MASTER_KEY_ID,
71+
usage = KeyUsage.MASTER_KEY,
72+
keyData = PublicKey.KeyData.CompressedEcKeyData(masterKey.toProto)
73+
)
74+
)
75+
)
76+
)
77+
)
78+
)
79+
)
80+
81+
expectedInitialState mustBe long.initialState
82+
}
83+
84+
"correctly generate suffix" in {
85+
val hash = Sha256Hash.compute(Array[Byte](0))
86+
val input = PrismDid.buildCanonical(Sha256Hash.compute(Array[Byte](0)))
87+
88+
hash.hexEncoded mustBe input.suffix
89+
}
90+
91+
"correctly build a valid did from empty canonical string" in {
92+
val validDid = PrismDid.buildCanonical(Sha256Hash.compute(Array[Byte](0)))
93+
val unsafeDid = PrismDid.fromString(validDid.value)
94+
95+
validDid mustBe unsafeDid
96+
}
97+
98+
"correctly build from valid long form DID" in {
99+
val longAsString = long.value
100+
val unsafeDid = PrismDid.fromString(longAsString)
101+
102+
long mustBe unsafeDid
103+
}
104+
105+
"correctly build from valid short form did" in {
106+
val canonicalAsString = short.value
107+
val unsafeDid = PrismDid.fromString(canonicalAsString)
108+
109+
short mustBe unsafeDid
110+
}
111+
112+
"parse prism did into a long form did and extract keys from DID data" in {
113+
val didString =
114+
"did:prism:1e8777cf1e014563b123d6eed984ff35d235f64497e6736b7b9647649b6afe8f:CmIKYBJeCgdtYXN0ZXIwEAFCUQoJc2VjcDI1NmsxEiEAwCb_BYvKwhcOIAWiguHbdBfRgJWVO9EvBgWGHPKn9wYaIQDYr0B_6ZsLlfhdE9Nv8-_sZP-l-u8UeUCSbucNiDrrrg"
115+
val prismDid = PrismDid.fromString(didString)
116+
assert(prismDid.isInstanceOf[LongFormPrismDid])
117+
118+
val prismState = prismDid.asInstanceOf[LongFormPrismDid].initialState
119+
val didData = prismState.operation.createDid.get.didData.value
120+
val publicKey = didData.publicKeys.head
121+
122+
val xProtoBytes = publicKey.getEcKeyData.x.toByteArray
123+
val yProtoBytes = publicKey.getEcKeyData.y.toByteArray
124+
xProtoBytes.length mustBe 33
125+
yProtoBytes.length mustBe 33
126+
}
127+
128+
"catch failure when parsing invalid DID" in {
129+
val caught = intercept[IllegalArgumentException] {
130+
PrismDid.fromString("invalid-did")
131+
}
132+
133+
assert(caught.getMessage == "Invalid DID format: invalid-did")
134+
}
135+
136+
"create canonical from string correctly" in {
137+
val shortAsString = short.value
138+
val unsafeDid = PrismDid.canonicalFromString(shortAsString)
139+
140+
short mustBe unsafeDid
141+
}
142+
143+
"fail when long form initial state is not CreateDid" in {
144+
val mockAtalaOperation =
145+
AtalaOperation(operation = AtalaOperation.Operation.UpdateDid(UpdateDIDOperation()))
146+
val updateDid = createLongFormDidFromAtalaOperationUnsafely(mockAtalaOperation)
147+
148+
val caught = intercept[CreateDidExpectedAsInitialState] {
149+
PrismDid.fromString(updateDid.did.toString())
150+
}
151+
152+
caught.getMessage mustBe "Provided initial state of long form Prism DID is UpdateDIDOperation(<ByteString@18e36d14 size=0 contents=\"\">,,Vector(),UnknownFieldSet(Map())), CreateDid Atala operation expected"
153+
154+
}
155+
156+
"fail for long form where master key is not present" in {
157+
val issuingPublicKey = CryptoTestUtils.generateKeyPair().publicKey
158+
val revocationPublicKey = CryptoTestUtils.generateKeyPair().publicKey
159+
160+
val issuingKeyPublicKey =
161+
PublicKey(
162+
id = PrismDid.DEFAULT_ISSUING_KEY_ID,
163+
usage = KeyUsage.ISSUING_KEY,
164+
keyData = PublicKey.KeyData.CompressedEcKeyData(issuingPublicKey.toProto)
165+
)
166+
val revocationKeyPublicKey =
167+
PublicKey(
168+
id = PrismDid.DEFAULT_REVOCATION_KEY_ID,
169+
usage = KeyUsage.REVOCATION_KEY,
170+
keyData = PublicKey.KeyData.CompressedEcKeyData(revocationPublicKey.toProto)
171+
)
172+
173+
val createDidOp = CreateDIDOperation(
174+
didData = Some(
175+
CreateDIDOperation.DIDCreationData(
176+
publicKeys = List(issuingKeyPublicKey, revocationKeyPublicKey)
177+
)
178+
)
179+
)
180+
181+
val noMasterKeyCreateDid =
182+
AtalaOperation(operation = AtalaOperation.Operation.CreateDid(createDidOp))
183+
val longForm = createLongFormDidFromAtalaOperationUnsafely(noMasterKeyCreateDid)
184+
185+
val caught = intercept[IllegalArgumentException] {
186+
PrismDid.fromString(longForm.did.toString())
187+
}
188+
189+
caught.getMessage mustBe "requirement failed: At least one public key with master role required"
190+
191+
}
27192

28193
}
29194
}

0 commit comments

Comments
 (0)