Skip to content

Commit

Permalink
feat(dataverse): add secp256k1 crypto support
Browse files Browse the repository at this point in the history
  • Loading branch information
amimart committed Feb 9, 2024
1 parent 8532682 commit 47462be
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 32 deletions.
19 changes: 6 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions contracts/okp4-dataverse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ cosmwasm-storage.workspace = true
cw-storage-plus.workspace = true
cw-utils.workspace = true
cw2.workspace = true
ed25519-compact = { version = "2.0.6", default-features = false, features = [
"std",
] }
itertools = "0.12.1"
multibase = "0.9.1"
okp4-cognitarium.workspace = true
Expand Down
8 changes: 4 additions & 4 deletions contracts/okp4-dataverse/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub fn instantiate(

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
_deps: DepsMut<'_>,
deps: DepsMut<'_>,
_env: Env,
_info: MessageInfo,
msg: ExecuteMsg,
Expand All @@ -74,7 +74,7 @@ pub fn execute(
ExecuteMsg::SubmitClaims {
metadata,
format: _,
} => execute::submit_claims(metadata),
} => execute::submit_claims(deps, metadata),
_ => Err(StdError::generic_err("Not implemented").into()),
}
}
Expand All @@ -86,13 +86,13 @@ pub mod execute {
use okp4_rdf::serde::NQuadsReader;
use std::io::BufReader;

pub fn submit_claims(data: Binary) -> Result<Response, ContractError> {
pub fn submit_claims(deps: DepsMut<'_>, data: Binary) -> Result<Response, ContractError> {
let buf = BufReader::new(data.as_slice());
let mut reader = NQuadsReader::new(buf);
let rdf_quads = reader.read_all()?;
let vc_dataset = Dataset::from(rdf_quads.as_slice());
let vc = VerifiableCredential::try_from(&vc_dataset)?;
vc.verify()?;
vc.verify(deps)?;

Ok(Response::default())
}
Expand Down
50 changes: 40 additions & 10 deletions contracts/okp4-dataverse/src/credential/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::credential::error::VerificationError;
use ed25519_compact::{PublicKey, Signature};
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
use base64::Engine;
use cosmwasm_std::DepsMut;
use okp4_rdf::normalize::Normalizer;
use rio_api::model::Quad;
use sha2::Digest;
use std::str::from_utf8;

pub enum CanonicalizationAlg {
Urdna2015,
Expand All @@ -14,6 +17,7 @@ pub enum DigestAlg {

pub enum SignatureAlg {
Ed25519,
Secp256k1,
}

pub struct CryptoSuite {
Expand All @@ -35,6 +39,7 @@ impl From<(CanonicalizationAlg, DigestAlg, SignatureAlg)> for CryptoSuite {
impl CryptoSuite {
pub fn verify_document(
&self,
deps: DepsMut<'_>,
unsecured_doc: &[Quad<'_>],
proof_opts: &[Quad<'_>],
proof_value: &[u8],
Expand All @@ -45,7 +50,7 @@ impl CryptoSuite {

let hash = [self.hash(proof_opts_canon), self.hash(unsecured_doc_canon)].concat();

self.verify(&hash, proof_value, pub_key)
self.verify(deps, &hash, proof_value, pub_key)
}

fn canonicalize(&self, unsecured_document: &[Quad<'_>]) -> Result<String, VerificationError> {
Expand All @@ -72,19 +77,44 @@ impl CryptoSuite {

fn verify(
&self,
deps: DepsMut<'_>,
message: &[u8],
signature: &[u8],
pub_key: &[u8],
) -> Result<(), VerificationError> {
match self.sign {
SignatureAlg::Ed25519 => {
let pub_key = PublicKey::from_slice(pub_key).map_err(VerificationError::from)?;
let signature =
Signature::from_slice(signature).map_err(VerificationError::from)?;
pub_key
.verify(message, &signature)
.map_err(VerificationError::from)
match match self.sign {
SignatureAlg::Ed25519 => deps.api.ed25519_verify(message, signature, pub_key),
SignatureAlg::Secp256k1 => {
let (headers_b64, signature_b64) = Self::explode_jws(signature)?;
let signature = BASE64_URL_SAFE_NO_PAD
.decode(signature_b64)
.map_err(|_| VerificationError::InvalidJws)?;

let signing_input = [headers_b64, b".", message].concat();
let mut hasher = sha2::Sha256::new();
hasher.update(signing_input);
let signing_input = hasher.finalize().to_vec();

let res = deps
.api
.secp256k1_verify(&signing_input, &signature, pub_key);
res
}
} {
Ok(true) => Ok(()),
Ok(false) => Err(VerificationError::WrongSignature),
Err(e) => Err(VerificationError::from(e)),
}
}

fn explode_jws(jws: &[u8]) -> Result<(&[u8], &[u8]), VerificationError> {
let jws = from_utf8(jws).map_err(|_| VerificationError::InvalidJws)?;
let mut parts = jws.split(".");
Ok(
match (parts.next(), parts.next(), parts.next(), parts.next()) {
(Some(headers), Some(_), Some(sig), None) => (headers.as_bytes(), sig.as_bytes()),
_ => Err(VerificationError::InvalidJws)?,
},
)
}
}
11 changes: 10 additions & 1 deletion contracts/okp4-dataverse/src/credential/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub enum InvalidProofError {
#[error("Missing proof value")]
MissingProofValue,

#[error("Missing proof cryptosuite")]
MissingProofCryptosuite,

#[error("Malformed proof value: {0}")]
MalformedProofValue(#[from] multibase::Error),

Expand All @@ -59,7 +62,13 @@ pub enum VerificationError {
RdfCanonError(#[from] NormalizationError),

#[error("Couldn't verify signature: {0}")]
SignatureError(#[from] ed25519_compact::Error),
SignatureError(#[from] cosmwasm_std::VerificationError),

#[error("Invalid JWS")]
InvalidJws,

#[error("Signature mismatch")]
WrongSignature,

#[error("Couldn't find a suitable proof")]
NoSuitableProof,
Expand Down
4 changes: 3 additions & 1 deletion contracts/okp4-dataverse/src/credential/vc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::credential::error::{InvalidCredentialError, InvalidProofError, VerificationError};
use crate::credential::proof::{Proof, ProofPurpose};
use crate::credential::rdf_marker::*;
use cosmwasm_std::DepsMut;
use itertools::Itertools;
use okp4_rdf::dataset::QuadIterator;
use okp4_rdf::dataset::{Dataset, QuadPattern};
Expand Down Expand Up @@ -73,7 +74,7 @@ impl<'a> TryFrom<&'a Dataset<'a>> for VerifiableCredential<'a> {
}

impl<'a> VerifiableCredential<'a> {
pub fn verify(&self) -> Result<(), VerificationError> {
pub fn verify(&self, deps: DepsMut<'_>) -> Result<(), VerificationError> {
let proof = self
.proof
.iter()
Expand All @@ -82,6 +83,7 @@ impl<'a> VerifiableCredential<'a> {

let crypto_suite = proof.crypto_suite();
crypto_suite.verify_document(
deps,
self.unsecured_document.as_ref(),
proof.options(),
proof.signature(),
Expand Down

0 comments on commit 47462be

Please sign in to comment.