如何在 Rust 中进行加密签名以避免 Python 调用

How to do cryptographic signature in Rust to avoid Python call

为什么在这段代码的底部,我需要使用以下模式:

        let a = urlpath.to_string();
        let b = nonce.to_string();
        let c = ordertype.to_string();
        let d = pair.to_string();
        let e = price.to_string();
        let f = type_.to_string();
        let g = volume.to_string();
        let h = api_sec.to_string();
        let kwargs = vec![("cmd", "account_balance"), ("urlpath", &a), ("nonce", &b), ("ordertype", &c), ("pair", &d), ("price", &e), ("type", &f), ("volume", &g), ("secret", &h)];

如果我替换vec中的变量&a!使用 &urlpath.to_string() 然后它失败说一个临时值正在被删除并且稍后使用它。

但是,无论我是否添加额外的 let 语句,该表达式的计算结果不是相同的吗?我怎样才能使它更符合 Rust 的习惯?

use std::{time::{SystemTime, UNIX_EPOCH}};
use pyo3::types::IntoPyDict;

fn main() -> PyResult<()> {

    let urlpath = "/0/private/Balance";
    println!("{}", urlpath);
    let api_sec = "<REPLACE>";
    println!("{}", api_sec);
    let nonce =  SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis();
    println!("{}", nonce);
    let ordertype = "limit";
    println!("{}", ordertype);
    let pair = "XBTUSD";
    println!("{}", pair);
    let price: i32 = 37500;
    println!("{}", price);
    let type_ = "buy";
    println!("{}", type_);
    let volume = 1.25;
    println!("{}", volume);

    Python::with_gil(|py| {
        let fun: Py<PyAny> = PyModule::from_code(
            py,
            "
import urllib.parse
import hashlib
import hmac
import base64

def get_kraken_signature(*args, **kwargs):
    if args != ():
        print('called with args', args)
    if kwargs != {}:
        print('called with kwargs', kwargs)
    if args == () and kwargs == {}:
        print('called with no arguments')
    if kwargs[\"cmd\"] == \"account_balance\":
        urlpath = kwargs[\"urlpath\"]
        data = {
            \"nonce\": kwargs[\"nonce\"],
        }
        secret = kwargs[\"secret\"]
    elif kwargs[\"cmd\"] == \"send_order\":
        urlpath = kwargs[\"urlpath\"]
        data = {
            \"nonce\": kwargs[\"nonce\"],
            \"ordertype\": kwargs[\"ordertype\"], 
            \"pair\": kwargs[\"pair\"],
            \"price\": kwargs[\"price\"], 
            \"type\": kwargs[\"type\"],
            \"volume\": kwargs[\"volume\"],
        }
        secret = kwargs[\"secret\"]
    else:
        exit(0)

    postdata = urllib.parse.urlencode(data)
    encoded = (str(data['nonce']) + postdata).encode()
    message = urlpath.encode() + hashlib.sha256(encoded).digest()
    mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
    sigdigest = base64.b64encode(mac.digest())
    print(\"API-Sign: {}\".format(sigdigest.decode()))
    return sigdigest.decode()
",
            "",
            "",
        )?.getattr("get_kraken_signature")?.into();

        let a = urlpath.to_string();
        let b = nonce.to_string();
        let c = ordertype.to_string();
        let d = pair.to_string();
        let e = price.to_string();
        let f = type_.to_string();
        let g = volume.to_string();
        let h = api_sec.to_string();
        let kwargs = vec![("cmd", "account_balance"), ("urlpath", &a), ("nonce", &b), ("ordertype", &c), ("pair", &d), ("price", &e), ("type", &f), ("volume", &g), ("secret", &h)];
        let result = fun.call(py, (), Some(kwargs.into_py_dict(py)))?;

        println!("{}", result);
        Ok(())
    })
}

奖励:问题的第二部分是如何用惯用的 Rust 重写 Python 部分?我已经尝试过但失败了,所以如果任何加密专家可以提供帮助,那将会很有帮助。

第一部分:(解释)

因为 a 是值的所有者,并且您正在使用所有者传递引用,即使在执行后它仍将保留在范围内,但在您直接传递 &urlpath.to_string() 的情况下,没有任何所有者,一旦执行结束,该值将被删除,并且将有一个悬空引用,这是消息的原因。

第二部分:(Python 到 rust 转换)
我不是加密专家,但我尝试转换您提供的没有条件部分的相同脚本,并匹配 python 和 rust.

中的输出
extern crate url;
extern crate base64;
// use std::time::{SystemTime, UNIX_EPOCH};
use url::form_urlencoded;
use sha2::{Sha256, Digest};

extern crate ring;
extern crate data_encoding;

use ring::hmac;
use data_encoding::BASE64;
use std::collections::HashMap;

fn main() {
    let urlpath = String::from("/0/private/Balance");
    // let nonce = SystemTime::now()
    //     .duration_since(UNIX_EPOCH)
    //     .expect("Time went backwards")
    //     .as_millis();
    let nonce: &str = &(1645371362680 as i64).to_string();

    let mut data = HashMap::new();
    data.insert("nonce", nonce);

     let postdata: String = form_urlencoded::Serializer::new(String::new())
        .extend_pairs(data.iter())
        .finish();
    let encoded = format!("{}{}", nonce, postdata);
    let message: Vec<u8> = [urlpath.as_bytes(), Sha256::digest(encoded.as_bytes()).as_ref()].concat();

    let secret_key = String::from("secret");
    let signed_key = hmac::Key::new(hmac::HMAC_SHA512, secret_key.as_bytes());
    let signature = hmac::sign(&signed_key, &message);
    let b64_encoded_sig = BASE64.encode(signature.as_ref());
    println!("Output: {}", b64_encoded_sig);
}

Playground