#![no_std]
#![cfg_attr(feature = "docs", feature(doc_cfg))]
mod tests;
use soroban_sdk::{
serde::Serialize, unwrap::UnwrapOptimized, BytesN, Env, IntoVal, RawVal, Symbol, Vec,
};
pub mod testutils;
mod public_types;
pub use crate::public_types::{
AccountSignatures, Ed25519Signature, Identifier, Signature, SignaturePayload,
SignaturePayloadV0,
};
const MAX_ACCOUNT_SIGNATURES: u32 = 20;
fn verify_ed25519_signature(env: &Env, auth: &Ed25519Signature, name: Symbol, args: Vec<RawVal>) {
let msg = SignaturePayloadV0 {
name,
contract: env.get_current_contract(),
network: env.ledger().network_passphrase(),
args,
};
let msg_bin = SignaturePayload::V0(msg).serialize(env);
env.verify_sig_ed25519(&auth.public_key, &msg_bin, &auth.signature);
}
fn verify_account_signatures(env: &Env, auth: &AccountSignatures, name: Symbol, args: Vec<RawVal>) {
let acc = env.accounts().get(&auth.account_id).unwrap_optimized();
let msg = SignaturePayloadV0 {
name,
contract: env.get_current_contract(),
network: env.ledger().network_passphrase(),
args,
};
let msg_bytes = SignaturePayload::V0(msg).serialize(env);
let threshold = acc.medium_threshold();
let mut weight = 0u32;
let sigs = &auth.signatures;
if sigs.len() > MAX_ACCOUNT_SIGNATURES {
panic!("too many account signatures");
}
let mut prev_pk: Option<BytesN<32>> = None;
for sig in sigs.iter().map(Result::unwrap) {
if let Some(prev) = prev_pk {
if prev == sig.public_key {
panic!("signature duplicate")
}
if prev > sig.public_key {
panic!("signature out of order")
}
}
env.verify_sig_ed25519(&sig.public_key, &msg_bytes, &sig.signature);
let signer_weight = acc.signer_weight(&sig.public_key);
if signer_weight == 0 {
panic!("signature doesn't belong to account");
}
let signer_weight: u32 = signer_weight.into();
weight += signer_weight;
prev_pk = Some(sig.public_key);
}
if weight < threshold.into() {
panic!("insufficient signing weight")
}
}
pub fn verify(env: &Env, sig: &Signature, name: Symbol, args: impl IntoVal<Env, Vec<RawVal>>) {
match sig {
Signature::Invoker => {}
Signature::Ed25519(e) => verify_ed25519_signature(env, &e, name, args.into_val(env)),
Signature::Account(a) => verify_account_signatures(env, &a, name, args.into_val(env)),
}
}