Skip to content

Commit

Permalink
Use verify account signature function from SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
DOBEN committed Oct 2, 2024
1 parent 34a6d42 commit 2a803e4
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 77 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The following examples are available.
interactions of a store that sells restricted items, and supports payment in
EUROe tokens (or generally any CIS2 token).

- [track-and-trace](./track-and-trace/) demonstrates an example frontend, backend, smart contract and event indexer to track items along the supply chain. It also has a [CIS-3](https://proposals.concordium.software/CIS/cis-3.html) sponsored transactions service that is compatible with any CIS-3 contract.
- [trackAndTrace](./trackAndTrace/) demonstrates an example frontend, backend, smart contract and event indexer to track items along the supply chain. It also has a [CIS-3](https://proposals.concordium.software/CIS/cis-3.html) sponsored transactions service that is compatible with any CIS-3 contract.

- [compliant-reward-distribution](./compliant-reward-distribution/) demonstrates an airdrop example with an indexer, a frontend, and a backend with signature and ZK proof verification at the backend. The ZK proof is used to ensure `Sybil-resistance/uniqueness` as each identity on the chain can interact with the service with only one of its accounts.

Expand Down
2 changes: 1 addition & 1 deletion compliant-reward-distribution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Hosted front end

[Soon](https://github.com/Concordium/concordium-dapp-examples)
[here](https://compliant-reward-distribution.testnet.concordium.com/)

## Overview

Expand Down
4 changes: 4 additions & 0 deletions compliant-reward-distribution/indexer-and-server/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Unreleased changes

## 0.1.1

- Change to use the new `verify_single_account_signature` function from the SDK.

## 0.1.0

- Add initial `server`.
Expand Down
12 changes: 6 additions & 6 deletions compliant-reward-distribution/indexer-and-server/Cargo.lock

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

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "indexer"
version = "0.1.0"
version = "0.1.1"
edition = "2021"

[dependencies]
Expand Down
79 changes: 13 additions & 66 deletions compliant-reward-distribution/indexer-and-server/src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ use axum::{
};
use chrono::Utc;
use clap::Parser;
use concordium_rust_sdk::smart_contracts::common::to_bytes;
use concordium_rust_sdk::{
id::{
constants::ArCurve,
id_proof_types::Statement,
types::{AccountAddress, AccountCredentialWithoutProofs},
},
signatures::verify_single_account_signature,
smart_contracts::common::to_bytes,
v2::{AccountIdentifier, BlockIdentifier, Client},
web3id::{
did::Network,
Expand Down Expand Up @@ -533,19 +534,10 @@ where
let SigningData {

Check warning on line 534 in compliant-reward-distribution/indexer-and-server/src/bin/server.rs

View workflow job for this annotation

GitHub Actions / Running formatting (compliant-reward-distribution/indexer-and-server/Cargo.toml)

Diff in /home/runner/work/concordium-dapp-examples/concordium-dapp-examples/compliant-reward-distribution/indexer-and-server/src/bin/server.rs
signer,
message,
signature,
signature,
block_height,
} = param.signing_data();

let signer_account_info = state
.node_client
.get_account_info(
&AccountIdentifier::Address(*signer),
BlockIdentifier::LastFinal,
)
.await
.map_err(ServerError::QueryError)?;

let block_hash = state
.node_client
.get_block_info(block_height)
Expand All @@ -565,63 +557,18 @@ where
message,
};

// The message signed in the Concordium wallet is prepended with the
// `account` address (signer) and 8 zero bytes. Accounts in the Concordium
// wallet can either sign a regular transaction (in that case the
// prepend is `account` address and the nonce of the account which is by
// design >= 1) or sign a message (in that case the prepend is `account`
// address and 8 zero bytes). Hence, the 8 zero bytes ensure that the user
// does not accidentally sign a transaction. The account nonce is of type
// u64 (8 bytes).
// Add the prepend to the message and calculate the final message hash.
let final_message_hash = sha2::Sha256::digest(
[
&signer.as_ref() as &[u8],
&[0u8; 8],
to_bytes(&message_signed_in_wallet).as_slice(),
]
.concat(),
);

// Get the public key of the signer.
let message_bytes = to_bytes(&message_signed_in_wallet);

// The intention is to only use/support regular accounts (no multi-sig
// accounts). While it works for some (but not all) multi-sig accounts, to
// reduce complexity we will communicate that multi-sig accounts are not
// supported. Regular accounts have only one public-private key pair at
// index 0 in the credential map.
if signer_account_info.response.account_credentials.len() != 1 {
return Err(ServerError::OnlyRegularAccounts);
}
let signer_account_credential = signer_account_info
.response
.account_credentials
.get(&0.into())
.ok_or(ServerError::OnlyRegularAccounts)?;

let signer_public_key = match &signer_account_credential.value {
// `Initial` accounts were created by identity providers in the past
// without a Pedersen commitment deployed on chain. As such we should not verify ZK proofs
// on them so that we exclude them from this service.
AccountCredentialWithoutProofs::Initial { .. } => {
return Err(ServerError::NoCredentialCommitment)
}
// We use/support regular accounts. Regular accounts have only one
// public-private key pair at index 0 in the key map.
AccountCredentialWithoutProofs::Normal { cdv, .. } => {
if cdv.cred_key_info.keys.len() != 1 {
return Err(ServerError::OnlyRegularAccounts);
}

cdv.cred_key_info
.keys
.get(&0.into())
.ok_or(ServerError::OnlyRegularAccounts)?
}
};
// Verify the signature.
let is_valid = verify_single_account_signature(
state.node_client.clone(),
*signer,
signature.clone(),
message_bytes,
BlockIdentifier::Best,
)
.await?;

// Verify the signature.
let is_valid = signer_public_key.verify(final_message_hash, signature);
if !is_valid {
return Err(ServerError::InvalidSignature);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use axum::{
use concordium_rust_sdk::{
base::{contracts_common::AccountAddressParseError, hashes::IncorrectLength},
common::types::AccountAddress,
signatures::SignatureError,
types::AbsoluteBlockHeight,
v2::QueryError,
web3id::{did::Network, CredentialLookupError, PresentationVerificationError},
Expand Down Expand Up @@ -120,6 +121,8 @@ pub enum ServerError {
AccountAddressParse(#[from] AccountAddressParseError),
#[error("Not a valid tweet URL (expected format: https://x.com/JohnDoe/status/1818198789817077916 or https://twitter.com/JohnDoe/status/1818198789817077916)")]
NotValidTweetURL,
#[error("Signature verification error: {0}")]
SignatureVerificationError(#[from] SignatureError),
}

impl IntoResponse for ServerError {
Expand Down Expand Up @@ -163,7 +166,8 @@ impl IntoResponse for ServerError {
| ServerError::NoCredentialCommitment
| ServerError::IdentityReUsed { .. }
| ServerError::AccountAddressParse(_)
| ServerError::NotValidTweetURL => {
| ServerError::NotValidTweetURL
| ServerError::SignatureVerificationError(..) => {
let error_message = format!("Bad request: {self}");
tracing::info!(error_message);
(StatusCode::BAD_REQUEST, error_message.into())
Expand Down

0 comments on commit 2a803e4

Please sign in to comment.