Functional Weave
Code in Python

crypto.hmac-sha256@1.0.0

impl/rust.rs

1,771 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::crypto_sha256::sha256;  ← from crypto.sha256 ^1.0.0 · built alongside by fune

const BLOCK: usize = 64;

fn check_bytes(value: &[i64], name: &str) {
    if value.iter().any(|b| !(0..=255).contains(b)) {
        panic!("{} must be a list of integers from 0 to 255", name);
    }
}

/// HMAC-SHA256 (RFC 2104): H((K ^ opad) || H((K ^ ipad) || message)), with a
/// key longer than the 64-byte block hashed down to 32 bytes first.
///
/// # Panics
/// Panics if any key or message value is outside 0-255.
pub fn hmac_sha256(key: &[i64], message: &[i64]) -> Vec<i64> {
    check_bytes(key, "key");
    check_bytes(message, "message");
    let hashed;
    let k: &[i64] = if key.len() > BLOCK {
        hashed = sha256(key);
        &hashed
    } else {
        key
    };
    let mut inner: Vec<i64> = Vec::with_capacity(BLOCK + message.len());
    let mut outer: Vec<i64> = Vec::with_capacity(BLOCK + 32);
    for i in 0..BLOCK {
        let b = if i < k.len() { k[i] } else { 0 };
        inner.push(b ^ 0x36);
        outer.push(b ^ 0x5c);
    }
    inner.extend_from_slice(message);
    outer.extend(sha256(&inner));
    sha256(&outer)
}

fn bytes_from_value(value: &Value, name: &str) -> Vec<i64> {
    match value {
        Value::Arr(items) => items
            .iter()
            .map(|item| match item {
                Value::Int(i) => *i,
                _ => panic!("{} must be a list of integers from 0 to 255", name),
            })
            .collect(),
        _ => panic!("{} must be a list of integers from 0 to 255", name),
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    let key = bytes_from_value(&args[0], "key");
    let message = bytes_from_value(&args[1], "message");
    Value::Arr(hmac_sha256(&key, &message).into_iter().map(Value::Int).collect())
}