Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
43 changes: 42 additions & 1 deletion crates/sui-indexer-alt-graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,20 @@ type Input {
}


"""
An enum that specifies the intent scope for signature verification.
"""
enum IntentScope {
"""
Indicates that the bytes are to be parsed as transaction data bytes.
"""
TRANSACTION_DATA
"""
Indicates that the bytes are to be parsed as a personal message.
"""
PERSONAL_MESSAGE
}

"""
Arbitrary JSON data.
"""
Expand Down Expand Up @@ -3681,6 +3695,23 @@ type Query {
"""
type(type: String!): MoveType
"""
Verify a signature is from the given `author`.
Supports all signature types: Ed25519, Secp256k1, Secp256r1, MultiSig, ZkLogin, and
Passkey.
Returns successfully if the signature is valid. If the signature is invalid, returns an
error with the reason for the failure.
- `message` is either a serialized personal message or `TransactionData`, Base64-encoded.
- `signature` is a serialized signature, also Base64-encoded.
- `intentScope` indicates whether `message` is to be parsed as a personal message or
`TransactionData`.
- `author` is an optional signer's address. If provided, the service validates that the
signature corresponds to this address.
"""
verifySignature(message: Base64!, signature: Base64!, intentScope: IntentScope!, author: SuiAddress): SignatureVerifyResult
"""
Verify a zkLogin signature is from the given `author`.
Returns successfully if the signature is valid. If the signature is invalid, returns an error with the reason for the failure.
Expand All @@ -3690,7 +3721,7 @@ type Query {
- `intentScope` indicates whether `bytes` are to be parsed as a personal message or `TransactionData`.
- `author` is the signer's address.
"""
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult @deprecated(reason: "Use `verifySignature` instead, which supports all signature types.")
}

"""
Expand Down Expand Up @@ -3976,6 +4007,16 @@ The structured details of a signature, varying by scheme.
"""
union SignatureScheme = Ed25519Signature | Secp256K1Signature | Secp256R1Signature | MultisigSignature | ZkLoginSignature | PasskeySignature

"""
The result of signature verification.
"""
type SignatureVerifyResult {
"""
Whether the signature was verified successfully.
"""
success: Boolean
}

"""
The result of simulating a transaction, including the predicted effects.
"""
Expand Down
85 changes: 85 additions & 0 deletions crates/sui-indexer-alt-graphql/src/api/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ use crate::api::types::object_filter::ObjectFilter;
use crate::api::types::object_filter::ObjectFilterValidator as OFValidator;
use crate::api::types::protocol_configs::ProtocolConfigs;
use crate::api::types::service_config::ServiceConfig;
use crate::api::types::signature_verify;
use crate::api::types::signature_verify::IntentScope;
use crate::api::types::signature_verify::SignatureVerifyResult;
use crate::api::types::simulation_result::SimulationResult;
use crate::api::types::transaction::CTransaction;
use crate::api::types::transaction::Transaction;
Expand Down Expand Up @@ -796,6 +799,87 @@ impl Query {
}
}

/// Verify a signature is from the given `author`.
///
/// Supports all signature types: Ed25519, Secp256k1, Secp256r1, MultiSig, ZkLogin, and
/// Passkey.
///
/// Returns successfully if the signature is valid. If the signature is invalid, returns an
/// error with the reason for the failure.
///
/// - `message` is either a serialized personal message or `TransactionData`, Base64-encoded.
/// - `signature` is a serialized signature, also Base64-encoded.
/// - `intentScope` indicates whether `message` is to be parsed as a personal message or
/// `TransactionData`.
/// - `author` is an optional signer's address. If provided, the service validates that the
/// signature corresponds to this address.
async fn verify_signature(
&self,
ctx: &Context<'_>,
message: Base64,
signature: Base64,
intent_scope: IntentScope,
author: Option<SuiAddress>,
) -> Option<Result<SignatureVerifyResult, RpcError<signature_verify::Error>>> {
Some(
async {
let fullnode_client: &FullnodeClient = ctx.data()?;

let bcs_message = match intent_scope {
IntentScope::TransactionData => {
proto::Bcs::from(message.0).with_name("TransactionData")
}
IntentScope::PersonalMessage => proto::Bcs::serialize(&message.0.as_slice())
.map_err(|e| {
bad_user_input(signature_verify::Error::InvalidArgument(format!(
"Failed to serialize personal message: {e}"
)))
})?
.with_name("PersonalMessage"),
};

let user_signature =
proto::UserSignature::default().with_bcs(proto::Bcs::from(signature.0));

let mut request = proto::VerifySignatureRequest::default()
.with_message(bcs_message)
.with_signature(user_signature);

if let Some(author) = author {
request = request.with_address(author.to_string());
}

match fullnode_client.verify_signature(request).await {
Ok(response) => {
if response.is_valid() {
Ok(SignatureVerifyResult {
success: Some(true),
})
} else {
let reason = response
.reason
.unwrap_or_else(|| "Unknown reason".to_string());
Err(bad_user_input(signature_verify::Error::VerificationFailed(
reason,
)))
}
}
Err(GrpcExecutionError(status))
if matches!(status.code(), Code::InvalidArgument) =>
{
Err(bad_user_input(signature_verify::Error::InvalidArgument(
status.message().to_string(),
)))
}
Err(other_error) => Err(anyhow!(other_error)
.context("Failed to verify signature")
.into()),
}
}
.await,
)
}

/// Verify a zkLogin signature is from the given `author`.
///
/// Returns successfully if the signature is valid. If the signature is invalid, returns an error with the reason for the failure.
Expand All @@ -804,6 +888,7 @@ impl Query {
/// - `signature` is a serialized zkLogin signature, also Base64-encoded.
/// - `intentScope` indicates whether `bytes` are to be parsed as a personal message or `TransactionData`.
/// - `author` is the signer's address.
#[graphql(deprecation = "Use `verifySignature` instead, which supports all signature types.")]
async fn verify_zk_login_signature(
&self,
ctx: &Context<'_>,
Expand Down
1 change: 1 addition & 0 deletions crates/sui-indexer-alt-graphql/src/api/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub(crate) mod open_move_type;
pub(crate) mod owner;
pub(crate) mod protocol_configs;
pub(crate) mod service_config;
pub(crate) mod signature_verify;
pub(crate) mod simulation_result;
pub(crate) mod transaction;
pub(crate) mod transaction_effects;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use async_graphql::Enum;
use async_graphql::SimpleObject;

/// An enum that specifies the intent scope for signature verification.
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
pub(crate) enum IntentScope {
/// Indicates that the bytes are to be parsed as transaction data bytes.
TransactionData,
/// Indicates that the bytes are to be parsed as a personal message.
PersonalMessage,
}

/// The result of signature verification.
#[derive(SimpleObject, Clone, Debug)]
pub(crate) struct SignatureVerifyResult {
/// Whether the signature was verified successfully.
pub success: Option<bool>,
}

#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
#[error("Verification failed: {0}")]
VerificationFailed(String),

#[error("Invalid argument: {0}")]
InvalidArgument(String),
}
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,9 @@ Query.type
Query.simulateTransaction
=> {}

Query.verifySignature
=> {}

Query.verifyZkLoginSignature
=> {}

Expand Down Expand Up @@ -1619,6 +1622,9 @@ SharedInput.initialSharedVersion
SharedInput.mutable
=> {}

SignatureVerifyResult.success
=> {}

SimulationResult.effects
=> {}

Expand Down
7 changes: 5 additions & 2 deletions crates/sui-indexer-alt-graphql/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ pub struct Limits {
pub max_output_nodes: u32,

/// Maximum size in bytes allowed for the `txBytes` and `signatures` parameters of an
/// `executeTransaction` or `simulateTransaction` field, or the `bytes` and `signature`
/// parameters of a `verifyZkLoginSignature` field.
/// `executeTransaction` or `simulateTransaction` field, the `message` and `signature`
/// parameters of a `verifySignature` field, or the `bytes` and `signature` parameters of a
/// `verifyZkLoginSignature` field.
///
/// This is cumulative across all matching fields in a single GraphQL request.
pub max_tx_payload_size: u32,
Expand Down Expand Up @@ -282,6 +283,8 @@ impl Limits {
("Mutation", "executeTransaction", "transactionDataBcs"),
("Mutation", "executeTransaction", "signatures"),
("Query", "simulateTransaction", "transaction"),
("Query", "verifySignature", "message"),
("Query", "verifySignature", "signature"),
("Query", "verifyZkLoginSignature", "bytes"),
("Query", "verifyZkLoginSignature", "signature"),
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,20 @@ type Input {
}


"""
An enum that specifies the intent scope for signature verification.
"""
enum IntentScope {
"""
Indicates that the bytes are to be parsed as transaction data bytes.
"""
TRANSACTION_DATA
"""
Indicates that the bytes are to be parsed as a personal message.
"""
PERSONAL_MESSAGE
}

"""
Arbitrary JSON data.
"""
Expand Down Expand Up @@ -3685,6 +3699,23 @@ type Query {
"""
type(type: String!): MoveType
"""
Verify a signature is from the given `author`.

Supports all signature types: Ed25519, Secp256k1, Secp256r1, MultiSig, ZkLogin, and
Passkey.

Returns successfully if the signature is valid. If the signature is invalid, returns an
error with the reason for the failure.

- `message` is either a serialized personal message or `TransactionData`, Base64-encoded.
- `signature` is a serialized signature, also Base64-encoded.
- `intentScope` indicates whether `message` is to be parsed as a personal message or
`TransactionData`.
- `author` is an optional signer's address. If provided, the service validates that the
signature corresponds to this address.
"""
verifySignature(message: Base64!, signature: Base64!, intentScope: IntentScope!, author: SuiAddress): SignatureVerifyResult
"""
Verify a zkLogin signature is from the given `author`.

Returns successfully if the signature is valid. If the signature is invalid, returns an error with the reason for the failure.
Expand All @@ -3694,7 +3725,7 @@ type Query {
- `intentScope` indicates whether `bytes` are to be parsed as a personal message or `TransactionData`.
- `author` is the signer's address.
"""
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult @deprecated(reason: "Use `verifySignature` instead, which supports all signature types.")
}

"""
Expand Down Expand Up @@ -3980,6 +4011,16 @@ The structured details of a signature, varying by scheme.
"""
union SignatureScheme = Ed25519Signature | Secp256K1Signature | Secp256R1Signature | MultisigSignature | ZkLoginSignature | PasskeySignature

"""
The result of signature verification.
"""
type SignatureVerifyResult {
"""
Whether the signature was verified successfully.
"""
success: Boolean
}

"""
The result of simulating a transaction, including the predicted effects.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,20 @@ type Input {
}


"""
An enum that specifies the intent scope for signature verification.
"""
enum IntentScope {
"""
Indicates that the bytes are to be parsed as transaction data bytes.
"""
TRANSACTION_DATA
"""
Indicates that the bytes are to be parsed as a personal message.
"""
PERSONAL_MESSAGE
}

"""
Arbitrary JSON data.
"""
Expand Down Expand Up @@ -3685,6 +3699,23 @@ type Query {
"""
type(type: String!): MoveType
"""
Verify a signature is from the given `author`.

Supports all signature types: Ed25519, Secp256k1, Secp256r1, MultiSig, ZkLogin, and
Passkey.

Returns successfully if the signature is valid. If the signature is invalid, returns an
error with the reason for the failure.

- `message` is either a serialized personal message or `TransactionData`, Base64-encoded.
- `signature` is a serialized signature, also Base64-encoded.
- `intentScope` indicates whether `message` is to be parsed as a personal message or
`TransactionData`.
- `author` is an optional signer's address. If provided, the service validates that the
signature corresponds to this address.
"""
verifySignature(message: Base64!, signature: Base64!, intentScope: IntentScope!, author: SuiAddress): SignatureVerifyResult
"""
Verify a zkLogin signature is from the given `author`.

Returns successfully if the signature is valid. If the signature is invalid, returns an error with the reason for the failure.
Expand All @@ -3694,7 +3725,7 @@ type Query {
- `intentScope` indicates whether `bytes` are to be parsed as a personal message or `TransactionData`.
- `author` is the signer's address.
"""
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult
verifyZkLoginSignature(bytes: Base64!, signature: Base64!, intentScope: ZkLoginIntentScope!, author: SuiAddress!): ZkLoginVerifyResult @deprecated(reason: "Use `verifySignature` instead, which supports all signature types.")
}

"""
Expand Down Expand Up @@ -3980,6 +4011,16 @@ The structured details of a signature, varying by scheme.
"""
union SignatureScheme = Ed25519Signature | Secp256K1Signature | Secp256R1Signature | MultisigSignature | ZkLoginSignature | PasskeySignature

"""
The result of signature verification.
"""
type SignatureVerifyResult {
"""
Whether the signature was verified successfully.
"""
success: Boolean
}

"""
The result of simulating a transaction, including the predicted effects.
"""
Expand Down
Loading
Loading