Skip to content

Commit

Permalink
Oberon NET SDK (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmarkovski committed Oct 8, 2021
1 parent 10c6bdb commit dfe3baa
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 12 deletions.
2 changes: 1 addition & 1 deletion dotnet/Library/Okapi/DIDKey.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Okapi.Keys
{
public class DIDKey
public static class DIDKey
{
/// <summary>
/// Generate new key
Expand Down
2 changes: 1 addition & 1 deletion dotnet/Library/Okapi/LDProofs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Okapi.Proofs
{
public class LDProofs
public static class LDProofs
{
/// <summary>
/// Generate new key
Expand Down
21 changes: 21 additions & 0 deletions dotnet/Library/Okapi/Native.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,26 @@ internal class Native
internal static extern int ldproofs_verify_proof(ByteBuffer request, out ByteBuffer response, out ExternError error);

#endregion

#region Oberon
[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_create_key(ByteBuffer request, out ByteBuffer response, out ExternError error);

[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_create_token(ByteBuffer request, out ByteBuffer response, out ExternError error);

[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_create_proof(ByteBuffer request, out ByteBuffer response, out ExternError error);

[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_verify_proof(ByteBuffer request, out ByteBuffer response, out ExternError error);

[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_blind_token(ByteBuffer request, out ByteBuffer response, out ExternError error);

[DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
internal static extern int oberon_unblind_token(ByteBuffer request, out ByteBuffer response, out ExternError error);

#endregion
}
}
23 changes: 23 additions & 0 deletions dotnet/Library/Okapi/Oberon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Okapi.Security
{
public static class Oberon
{
public static CreateOberonKeyResponse CreateKey(CreateOberonKeyRequest request) =>
Native.Call<CreateOberonKeyRequest, CreateOberonKeyResponse>(request, Native.oberon_create_key);

public static CreateOberonTokenResponse CreateToken(CreateOberonTokenRequest request) =>
Native.Call<CreateOberonTokenRequest, CreateOberonTokenResponse>(request, Native.oberon_create_token);

public static CreateOberonProofResponse CreateProof(CreateOberonProofRequest request) =>
Native.Call<CreateOberonProofRequest, CreateOberonProofResponse>(request, Native.oberon_create_proof);

public static VerifyOberonProofResponse VerifyProof(VerifyOberonProofRequest request) =>
Native.Call<VerifyOberonProofRequest, VerifyOberonProofResponse>(request, Native.oberon_verify_proof);

public static BlindOberonTokenResponse BlindToken(BlindOberonTokenRequest request) =>
Native.Call<BlindOberonTokenRequest, BlindOberonTokenResponse>(request, Native.oberon_blind_token);

public static UnBlindOberonTokenResponse UnblindToken(UnBlindOberonTokenRequest request) =>
Native.Call<UnBlindOberonTokenRequest, UnBlindOberonTokenResponse>(request, Native.oberon_unblind_token);
}
}
1 change: 1 addition & 0 deletions dotnet/Library/Okapi/Okapi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<Protobuf Include="..\..\..\proto\keys.proto" Link="Protobuf/keys.proto" />
<Protobuf Include="..\..\..\proto\transport.proto" Link="Protobuf/transport.proto" />
<Protobuf Include="..\..\..\proto\proofs.proto" Link="Protobuf/proofs.proto" />
<Protobuf Include="..\..\..\proto\security.proto" Link="Protobuf/security.proto" />
<Protobuf Include="..\..\..\proto\pbmse\pbmse.proto" Link="Protobuf/pbmse/pbmse.proto" />
<Protobuf Include="..\..\..\proto\examples.proto" Link="Protobuf/examples.proto" />
</ItemGroup>
Expand Down
16 changes: 8 additions & 8 deletions dotnet/Tests/Okapi.Tests/KeyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public void TestGenerateKeyNoSeed()
response.Key[0].Crv.Should().Be("Ed25519");
publicKey.Should().NotBeNull().And.HaveCount(32);
System.Convert.FromBase64String(base64toBase64Url(response.Key[0].D)).Should().NotBeNull().And.HaveCount(32);
}

}


[Fact(DisplayName = "Generate new key throws for invalid key type")]
public void TestGenerateKeyThrowsInvalidSeedSize()
{
Expand All @@ -50,18 +50,18 @@ public void TestGenerateKeyThrowsInvalidSeedSize()
{
KeyType = (KeyType)(-1)
})
);
}
);
}

[Fact(DisplayName = "Resolve a given key")]
public void TestResolveKey()
{
var response = DIDKey.Resolve(new ResolveRequest
{
Did =
"did:key:z6Mkt6QT8FPajKXDrtMefkjxRQENd9wFzKkDFomdQAVFzpzm#z6LSfDq6DuofPeZUqNEmdZsxpvfHvSoUXGEWFhw7JHk4cynN"
});
Assert.NotNull(response);
});
Assert.NotNull(response);
}


Expand Down
140 changes: 140 additions & 0 deletions dotnet/Tests/Okapi.Tests/OberonTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using Google.Protobuf;
using Okapi.Security;
using Xunit;

namespace Okapi.Tests
{
public class OberonTests {

[Fact]
public void TestDemo()
{
var key = Oberon.CreateKey(new CreateOberonKeyRequest());

var data = ByteString.CopyFromUtf8("alice");
var nonce = ByteString.CopyFromUtf8("1234");

var token = Oberon.CreateToken(new CreateOberonTokenRequest
{
Data = data,
Sk = key.Sk
});

var proof = Oberon.CreateProof(new CreateOberonProofRequest
{
Data = data,
Nonce = nonce,
Token = token.Token
});

var result = Oberon.VerifyProof(new VerifyOberonProofRequest
{
Data = data,
Nonce = nonce,
Pk = key.Pk,
Proof = proof.Proof
});

Assert.True(result.Valid);
}

[Fact]
public void TestDemoWithBlinding()
{
// Issuer generates oberon key pair
var key = Oberon.CreateKey(new CreateOberonKeyRequest());

var data = ByteString.CopyFromUtf8("alice");
var nonce = ByteString.CopyFromUtf8("1234");

// blinding code to be used by issuer and given to holder
// to transfer the token securely
var issuer_2fa = ByteString.CopyFromUtf8("issuer code");

CreateOberonTokenRequest tokenRequst = new()
{
Data = data,
Sk = key.Sk
};
tokenRequst.Blinding.Add(issuer_2fa);

var blindedToken = Oberon.CreateToken(tokenRequst);

// Holder unblinds the token
UnBlindOberonTokenRequest unblindRequest = new() { Token = blindedToken.Token };
unblindRequest.Blinding.Add(issuer_2fa);

var token = Oberon.UnblindToken(unblindRequest);

// Holder prepares a proof without blinding
var proof = Oberon.CreateProof(new CreateOberonProofRequest
{
Data = data,
Nonce = nonce,
Token = token.Token
});

// Verifier verifies the proof
var result = Oberon.VerifyProof(new VerifyOberonProofRequest
{
Data = data,
Nonce = nonce,
Pk = key.Pk,
Proof = proof.Proof
});

Assert.True(result.Valid);

// Holder blinds the token with a personal pin
var userPin = ByteString.CopyFromUtf8("0042");
BlindOberonTokenRequest blindRequest = new() { Token = token.Token };
blindRequest.Blinding.Add(userPin);

var userBlindedToken = Oberon.BlindToken(blindRequest);

// Holder prepares a proof using the pin blinding
CreateOberonProofRequest proofRequest = new()
{
Data = data,
Nonce = nonce,
Token = userBlindedToken.Token
};
proofRequest.Blinding.Add(userPin);

proof = Oberon.CreateProof(proofRequest);

// Verifier verifies the proof
result = Oberon.VerifyProof(new VerifyOberonProofRequest
{
Data = data,
Nonce = nonce,
Pk = key.Pk,
Proof = proof.Proof
});

Assert.True(result.Valid);

// Bad actor creates a proof with incorrect blinding pin
proofRequest = new()
{
Data = data,
Nonce = nonce,
Token = userBlindedToken.Token
};
proofRequest.Blinding.Add(ByteString.CopyFromUtf8("invalid pin"));

proof = Oberon.CreateProof(proofRequest);

// Verifier tries to verify proof, fails
result = Oberon.VerifyProof(new VerifyOberonProofRequest
{
Data = data,
Nonce = nonce,
Pk = key.Pk,
Proof = proof.Proof
});

Assert.False(result.Valid);
}
}
}
4 changes: 2 additions & 2 deletions dotnet/Tests/Okapi.Tests/Okapi.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.10.3"/>
<PackageReference Include="Multiformats.Base" Version="2.0.2"/>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Multiformats.Base" Version="2.0.2" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit dfe3baa

Please sign in to comment.