Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oberon NET SDK #187

Merged
merged 10 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions dotnet/Library/Okapi/Native.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,18 @@ 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_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);

#endregion
}
}
14 changes: 14 additions & 0 deletions dotnet/Library/Okapi/Oberon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Okapi.Security
{
public class Oberon
tmarkovski marked this conversation as resolved.
Show resolved Hide resolved
{
public static CreateOberonTokenReply CreateToken(CreateOberonTokenRequest request) =>
Native.Call<CreateOberonTokenRequest, CreateOberonTokenReply>(request, Native.oberon_create_proof);

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

public static VerifyOberonProofReply VerifyProof(VerifyOberonProofRequest request) =>
Native.Call<VerifyOberonProofRequest, VerifyOberonProofReply>(request, Native.oberon_verify_proof);
}
}
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>
tmarkovski marked this conversation as resolved.
Show resolved Hide resolved
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);
fundthmcalculus marked this conversation as resolved.
Show resolved Hide resolved
}


Expand Down
4 changes: 4 additions & 0 deletions dotnet/Tests/Okapi.Tests/OberonTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Okapi.Tests
{
public class OberonTests { }
fundthmcalculus marked this conversation as resolved.
Show resolved Hide resolved
}
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
12 changes: 12 additions & 0 deletions include/okapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ int32_t ldproofs_verify_proof(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t oberon_create_token(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t oberon_create_proof(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

int32_t oberon_verify_proof(struct ByteBuffer request,
struct ByteBuffer *response,
struct ExternError *err);

fundthmcalculus marked this conversation as resolved.
Show resolved Hide resolved
void didcomm_byte_buffer_free(struct ByteBuffer v);

void didcomm_string_free(char *s);
3 changes: 3 additions & 0 deletions native/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ serde_json = "1.0.60"
serde_jcs = "0.1.0"
sha2 = { version = "0.9", default-features = false }
bs58 = "0.3.1"
oberon = { git = "https://github.com/sethjback/oberon", branch = "fix_proof_bytes" }
rand = "0.8"
subtle = "2.4"

[lib]
name = "okapi"
Expand Down
3 changes: 3 additions & 0 deletions native/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ fn compile_protobuf_files() {
"../proto/examples.proto",
"../proto/keys.proto",
"../proto/proofs.proto",
"../proto/security.proto"
],
&["../proto", "../proto/pbmse"],
)
Expand All @@ -52,12 +53,14 @@ fn compile_protobuf_files() {
copy("okapi.keys.rs", "./src/proto/okapi_keys.rs").unwrap();
copy("okapi.transport.rs", "./src/proto/okapi_transport.rs").unwrap();
copy("okapi.proofs.rs", "./src/proto/okapi_proofs.rs").unwrap();
copy("okapi.security.rs", "./src/proto/okapi_security.rs").unwrap();
copy("google.protobuf.rs", "./src/proto/google_protobuf.rs").unwrap();
copy("pbmse.rs", "./src/proto/pbmse.rs").unwrap();
remove_file("okapi.examples.rs").unwrap();
remove_file("okapi.keys.rs").unwrap();
remove_file("okapi.transport.rs").unwrap();
remove_file("okapi.proofs.rs").unwrap();
remove_file("okapi.security.rs").unwrap();
remove_file("google.protobuf.rs").unwrap();
remove_file("pbmse.rs").unwrap();
}
1 change: 1 addition & 0 deletions native/src/ffi/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod didcomm;
pub mod didkey;
pub mod ldproofs;
pub mod oberon;
pub mod utils;
17 changes: 17 additions & 0 deletions native/src/ffi/oberon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::{proto::security::*, *};
use ffi_support::{ByteBuffer, ExternError};

#[no_mangle]
pub extern "C" fn oberon_create_token(request: ByteBuffer, response: &mut ByteBuffer, err: &mut ExternError) -> i32 {
c_impl!(CreateOberonTokenRequest, Oberon, token, request, response, err)
}

#[no_mangle]
pub extern "C" fn oberon_create_proof(request: ByteBuffer, response: &mut ByteBuffer, err: &mut ExternError) -> i32 {
c_impl!(CreateOberonProofRequest, Oberon, proof, request, response, err)
}

#[no_mangle]
pub extern "C" fn oberon_verify_proof(request: ByteBuffer, response: &mut ByteBuffer, err: &mut ExternError) -> i32 {
c_impl!(VerifyOberonProofRequest, Oberon, verify, request, response, err)
}
2 changes: 2 additions & 0 deletions native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use prost::{DecodeError, Message};
pub struct DIDComm {}
pub struct DIDKey {}
pub struct LdProofs {}
pub struct Oberon {}

#[allow(clippy::ptr_arg)]
pub trait MessageFormatter {
Expand Down Expand Up @@ -42,6 +43,7 @@ mod ffi;
#[cfg(not(target_arch = "wasm32"))]
mod jni;
mod ldproofs;
mod oberon;
pub mod proto;
#[cfg(test)]
mod tests;
Expand Down
96 changes: 96 additions & 0 deletions native/src/oberon/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::{proto::security::*, didcomm::Error};
use std::convert::TryInto;
use oberon;
use rand::prelude::*;

impl crate::Oberon{
pub fn token<'a>(request: &CreateOberonTokenRequest) -> Result<CreateOberonTokenReply, Error<'a>> {
if request.data.len() == 0 {
return Err(Error::InvalidField("must provide data"))
}

let skbytes: [u8; oberon::SecretKey::BYTES] = match request.sk.as_slice().try_into() {
Ok(skbytes) => skbytes,
Err(_) => return Err(Error::InvalidField("invalid secret key provided"))
};

let sk = oberon::SecretKey::from(&skbytes);
let mut token = match oberon::Token::new(&sk, &request.data) {
None => return Err(Error::InvalidField("invalid data provided")),
Some(token) => token
};

let blind_iter = request.blinding.iter();
for blind in blind_iter {
let b = oberon::Blinding::new(&blind);
token = token - b;
}

Ok(CreateOberonTokenReply {
token: token.to_bytes().to_vec()
})
}

pub fn proof<'a>(request: &CreateOberonProofRequest) -> Result<CreateOberonProofReply, Error<'a>> {
if request.data.len() == 0 {
return Err(Error::InvalidField("must provide data"))
}

let tokenbytes: [u8; oberon::Token::BYTES] = match request.token.as_slice().try_into() {
Ok(tokenbytes) => tokenbytes,
Err(_) => return Err(Error::InvalidField("invalid token provided"))
};

let tk = oberon::Token::from_bytes(&tokenbytes);
if tk.is_none().into() {
return Err(Error::InvalidField("invalid token provided"))
}

let blinds: Vec<oberon::Blinding> = request.blinding.iter().map(|v|{
oberon::Blinding::new(&v)
}).collect();

let mut rng = thread_rng();

let proof = match oberon::Proof::new(&tk.unwrap(), &blinds, &request.data, &request.nonce, &mut rng) {
None => return Err(Error::Unknown),
Some(proof) => proof,
};

Ok(CreateOberonProofReply{
proof: proof.to_bytes().to_vec()
})
}

pub fn verify<'a>(request: &VerifyOberonProofRequest) -> Result<VerifyOberonProofReply, Error<'a>> {
if request.data.len() == 0 {
return Err(Error::InvalidField("must provide data"))
}

let pkbytes: [u8; oberon::PublicKey::BYTES] = match request.pk.as_slice().try_into() {
Ok(pkbytes) => pkbytes,
Err(_) => return Err(Error::InvalidField("invalid public key provided"))
};

let pk = oberon::PublicKey::from_bytes(&pkbytes);
if pk.is_none().into() {
return Err(Error::InvalidField("invalid public key provided"))
}

let proofbytes: [u8; oberon::Proof::BYTES] = match request.proof.as_slice().try_into() {
Ok(proofbytes) => proofbytes,
Err(_) => return Err(Error::InvalidField("invalid proof provided"))
};

let proof = oberon::Proof::from_bytes(&proofbytes);
if proof.is_none().into() {
return Err(Error::InvalidField("invalid proof provided"))
}

let valid = proof.unwrap().open(pk.unwrap(), &*request.data, &request.nonce);

Ok(VerifyOberonProofReply{
valid: valid.into()
})
}
}
4 changes: 4 additions & 0 deletions native/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,11 @@ pub mod transport {
pub mod proofs {
pub use crate::proto::okapi_proofs::*;
}
pub mod security {
pub use crate::proto::okapi_security::*;
}
pub mod okapi_keys;
pub mod okapi_proofs;
pub mod okapi_transport;
pub mod okapi_security;
pub mod pbmse;
72 changes: 72 additions & 0 deletions native/src/proto/okapi_security.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/// Create a new oberon token
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateOberonTokenRequest {
/// raw BLS key bytes
#[prost(bytes="vec", tag="1")]
pub sk: ::prost::alloc::vec::Vec<u8>,
/// data is the public part of the oberon protocol and can be any data
#[prost(bytes="vec", tag="2")]
pub data: ::prost::alloc::vec::Vec<u8>,
/// optional blinding for the token
#[prost(bytes="vec", repeated, tag="3")]
pub blinding: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
}
/// Contains the token with optional blinding
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateOberonTokenReply {
/// raw token bytes
#[prost(bytes="vec", tag="1")]
pub token: ::prost::alloc::vec::Vec<u8>,
}
/// Create a proof that holder knows the token
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateOberonProofRequest {
/// data used to create the token
#[prost(bytes="vec", tag="1")]
pub data: ::prost::alloc::vec::Vec<u8>,
/// token data
#[prost(bytes="vec", tag="2")]
pub token: ::prost::alloc::vec::Vec<u8>,
/// any blindings used to create the token
#[prost(bytes="vec", repeated, tag="3")]
pub blinding: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
/// nonce for generating the proof
#[prost(bytes="vec", tag="4")]
pub nonce: ::prost::alloc::vec::Vec<u8>,
}
/// Contains the token proof
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CreateOberonProofReply {
/// raw proof bytes
#[prost(bytes="vec", tag="2")]
pub proof: ::prost::alloc::vec::Vec<u8>,
}
/// Verify the presented proof is valid
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct VerifyOberonProofRequest {
/// raw proof bytes returned from CreateProof
#[prost(bytes="vec", tag="1")]
pub proof: ::prost::alloc::vec::Vec<u8>,
/// data used to create the token
#[prost(bytes="vec", tag="2")]
pub data: ::prost::alloc::vec::Vec<u8>,
/// nonce used to generate the proof
#[prost(bytes="vec", tag="3")]
pub nonce: ::prost::alloc::vec::Vec<u8>,
/// public key that was used to generate the token
#[prost(bytes="vec", tag="4")]
pub pk: ::prost::alloc::vec::Vec<u8>,
}
/// Contains the status of the proof validation
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct VerifyOberonProofReply {
/// whether the given proof was valid
#[prost(bool, tag="1")]
pub valid: bool,
}
1 change: 1 addition & 0 deletions native/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod keys;
pub mod pack;
pub mod sign;
pub mod oberon;
Loading