use crate::{Blinding, Proof, PublicKey, SecretKey, Token};
#[cfg_attr(windows, feature(abi_vectorcall))]
use ext_php_rs::prelude::*;
use rand::thread_rng;
use ext_php_rs::zend::ModuleEntry;
use ext_php_rs::{info_table_end, info_table_row, info_table_start};
use std::{convert::TryFrom, string::String, vec::Vec};
#[php_function]
pub fn oberon_new_secret_key() -> Vec<u8> {
let rng = thread_rng();
SecretKey::new(rng).to_bytes().to_vec()
}
#[php_function]
pub fn oberon_get_public_key(sk: Vec<u8>) -> Option<Vec<u8>> {
match secret_key(sk) {
None => None,
Some(sk) => Some(PublicKey::from(&sk).to_bytes().to_vec()),
}
}
#[php_function]
pub fn oberon_secret_key_from_seed(seed: Vec<u8>) -> Vec<u8> {
SecretKey::hash(&seed).to_bytes().to_vec()
}
#[php_function]
pub fn oberon_new_token(sk: Vec<u8>, id: String) -> Option<Vec<u8>> {
match secret_key(sk) {
None => None,
Some(sk) => Some(Token::new(&sk, id.as_bytes()).unwrap().to_bytes().to_vec()),
}
}
#[php_function]
pub fn oberon_verify_token(token: Vec<u8>, pk: Vec<u8>, id: String) -> bool {
match (get_token(token), public_key(pk)) {
(Some(t), Some(k)) => t.verify(k, id.as_bytes()).unwrap_u8() == 1,
(_, _) => false,
}
}
#[php_function]
pub fn oberon_create_blinding(data: Vec<u8>) -> Vec<u8> {
Blinding::new(&data).to_bytes().to_vec()
}
#[php_function]
pub fn oberon_add_blinding(token: Vec<u8>, data: Vec<u8>) -> Option<Vec<u8>> {
match get_token(token) {
None => None,
Some(t) => {
let val = t - Blinding::new(&data);
Some(val.to_bytes().to_vec())
}
}
}
#[php_function]
pub fn oberon_remove_blinding(token: Vec<u8>, data: Vec<u8>) -> Option<Vec<u8>> {
match get_token(token) {
None => None,
Some(t) => {
let val = t + Blinding::new(&data);
Some(val.to_bytes().to_vec())
}
}
}
#[php_function]
pub fn oberon_create_proof(
token: Vec<u8>,
id: String,
blindings: Vec<Vec<u8>>,
nonce: Vec<u8>,
) -> Option<Vec<u8>> {
let bs: Vec<Blinding> = blindings.iter().map(|b| Blinding::new(b)).collect();
let rng = thread_rng();
match get_token(token) {
None => None,
Some(t) => Proof::new(&t, &bs, id.as_bytes(), nonce, rng).map(|p| p.to_bytes().to_vec()),
}
}
#[php_function]
pub fn oberon_verify_proof(proof: Vec<u8>, pk: Vec<u8>, id: String, nonce: Vec<u8>) -> bool {
match (get_proof(proof), public_key(pk)) {
(Some(p), Some(k)) => p.open(k, id.as_bytes(), nonce).unwrap_u8() == 1,
(_, _) => false,
}
}
macro_rules! from_bytes {
($name:ident, $type:ident) => {
fn $name(input: Vec<u8>) -> Option<$type> {
match <[u8; $type::BYTES]>::try_from(input.as_slice()) {
Err(_) => None,
Ok(bytes) => {
let val = $type::from_bytes(&bytes);
if val.is_some().unwrap_u8() == 1u8 {
Some(val.unwrap())
} else {
None
}
}
}
}
};
}
from_bytes!(secret_key, SecretKey);
from_bytes!(public_key, PublicKey);
from_bytes!(get_token, Token);
from_bytes!(get_proof, Proof);
#[no_mangle]
pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
info_table_start!();
info_table_row!("oberon extension", "enabled");
info_table_end!();
}
#[php_module]
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
module.info_function(php_module_info)
}