optee-utee/src/arithmetical.rs (266 lines of code) (raw):
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::{Error, Result};
use optee_utee_sys as raw;
use core::{cmp::max, fmt};
#[cfg(not(target_os = "optee"))]
use alloc::vec::Vec;
pub type BigIntUnit = u32;
pub type BigIntFMMUnit = u32;
pub type BigIntFMMContextUnit = u32;
pub struct BigInt(Vec<BigIntUnit>);
impl BigInt {
pub fn data_ptr(&self) -> *const u32 {
self.0.as_ptr()
}
// size represents BigInt bits
pub fn size_in_u32(size: u32) -> u32 {
return ((size + 31) / 32) + 2;
}
pub fn new(bits: u32) -> Self {
let size: usize = Self::size_in_u32(bits) as usize;
let mut tmp_vec: Vec<BigIntUnit> = vec![0; size];
unsafe { raw::TEE_BigIntInit(tmp_vec.as_mut_ptr(), size as usize) };
Self(tmp_vec)
}
pub fn convert_from_octet_string(&mut self, buffer: &[u8], sign: i32) -> Result<()> {
match unsafe {
raw::TEE_BigIntConvertFromOctetString(
self.0.as_mut_ptr(),
buffer.as_ptr(),
buffer.len() as usize,
sign,
)
} {
raw::TEE_SUCCESS => Ok(()),
code => Err(Error::from_raw_error(code)),
}
}
pub fn convert_to_octet_string(&self) -> Result<Vec<u8>> {
let mut buffer_size: usize = (self.0.len() - 2) * 4;
let mut tmp_vec = vec![0u8; buffer_size];
match unsafe {
raw::TEE_BigIntConvertToOctetString(
tmp_vec.as_mut_ptr(),
&mut buffer_size,
self.data_ptr(),
)
} {
raw::TEE_SUCCESS => {
tmp_vec.truncate(buffer_size);
return Ok(tmp_vec);
}
code => Err(Error::from_raw_error(code)),
}
}
pub fn convert_from_s32(&mut self, short_val: i32) {
unsafe { raw::TEE_BigIntConvertFromS32(self.0.as_mut_ptr(), short_val) };
}
pub fn convert_to_s32(&self) -> Result<i32> {
let mut short_val: i32 = 0;
match unsafe { raw::TEE_BigIntConvertToS32(&mut short_val as _, self.data_ptr()) } {
raw::TEE_SUCCESS => Ok(short_val),
code => Err(Error::from_raw_error(code)),
}
}
/* return negative number if self < target,
0 if self == target
positive number if self > target*/
pub fn compare_big_int(&self, target: &Self) -> i32 {
unsafe { raw::TEE_BigIntCmp(self.data_ptr(), target.data_ptr()) }
}
pub fn compare_s32(&self, target: i32) -> i32 {
unsafe { raw::TEE_BigIntCmpS32(self.data_ptr(), target) }
}
pub fn shift_right(&mut self, op: &Self, bits: usize) {
// Should return a BigInt, while its size is based on the abs function which is missed
// right now
unsafe { raw::TEE_BigIntShiftRight(self.0.as_mut_ptr(), op.data_ptr(), bits) };
}
pub fn get_bit(&self, bit_index: u32) -> bool {
unsafe { raw::TEE_BigIntGetBit(self.data_ptr(), bit_index) }
}
pub fn get_bit_count(&self) -> u32 {
unsafe { raw::TEE_BigIntGetBitCount(self.data_ptr()) }
}
pub fn add(op1: &Self, op2: &Self) -> Self {
let bits = max(Self::get_bit_count(op1), Self::get_bit_count(op2)) + 1;
let mut res = Self::new(bits);
unsafe { raw::TEE_BigIntAdd(res.0.as_mut_ptr(), op1.data_ptr(), op2.data_ptr()) };
res
}
pub fn sub(op1: &Self, op2: &Self) -> Self {
let bits = max(Self::get_bit_count(op1), Self::get_bit_count(op2)) + 1;
let mut res = Self::new(bits);
unsafe { raw::TEE_BigIntSub(res.0.as_mut_ptr(), op1.data_ptr(), op2.data_ptr()) };
res
}
pub fn neg(op: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(op));
unsafe { raw::TEE_BigIntNeg(res.0.as_mut_ptr(), op.data_ptr()) };
res
}
pub fn multiply(op1: &Self, op2: &Self) -> Self {
let bits = Self::get_bit_count(op1) + Self::get_bit_count(op2);
let mut res = Self::new(bits);
unsafe { raw::TEE_BigIntMul(res.0.as_mut_ptr(), op1.data_ptr(), op2.data_ptr()) };
res
}
pub fn square(op: &Self) -> Self {
let mut res = Self::new(2 * Self::get_bit_count(op));
unsafe { raw::TEE_BigIntSquare(res.0.as_mut_ptr(), op.data_ptr()) };
res
}
// document defines wrong size for result quotient
pub fn divide(op1: &Self, op2: &Self) -> (Self, Self) {
let q_bits = match op1.compare_big_int(op2) {
d if d >= 0 => max(1, Self::get_bit_count(op1) - Self::get_bit_count(op2)),
_ => 0,
};
let r_bits = Self::get_bit_count(op2);
let mut quotient = Self::new(q_bits);
let mut remainder = Self::new(r_bits);
unsafe {
raw::TEE_BigIntDiv(
quotient.0.as_mut_ptr(),
remainder.0.as_mut_ptr(),
op1.data_ptr(),
op2.data_ptr(),
)
};
(quotient, remainder)
}
pub fn module(op: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe { raw::TEE_BigIntMod(res.0.as_mut_ptr(), op.data_ptr(), n.data_ptr()) };
res
}
pub fn add_mod(op1: &Self, op2: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe {
raw::TEE_BigIntAddMod(
res.0.as_mut_ptr(),
op1.data_ptr(),
op2.data_ptr(),
n.data_ptr(),
)
};
res
}
pub fn sub_mod(op1: &Self, op2: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe {
raw::TEE_BigIntSubMod(
res.0.as_mut_ptr(),
op1.data_ptr(),
op2.data_ptr(),
n.data_ptr(),
)
};
res
}
pub fn mul_mod(op1: &Self, op2: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe {
raw::TEE_BigIntMulMod(
res.0.as_mut_ptr(),
op1.data_ptr(),
op2.data_ptr(),
n.data_ptr(),
)
};
res
}
pub fn square_mod(op: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe { raw::TEE_BigIntSquareMod(res.0.as_mut_ptr(), op.data_ptr(), n.data_ptr()) };
res
}
pub fn inv_mod(op: &Self, n: &Self) -> Self {
let mut res = Self::new(Self::get_bit_count(n));
unsafe { raw::TEE_BigIntInvMod(res.0.as_mut_ptr(), op.data_ptr(), n.data_ptr()) };
res
}
pub fn relative_prime(op1: &Self, op2: &Self) -> bool {
unsafe { raw::TEE_BigIntRelativePrime(op1.data_ptr(), op2.data_ptr()) }
}
/* pub fn compute_extended_gcd(op1: &Self, op2: &Self) -> (Self, Self, Self)
* This function is implemented in OP-TEE, while the output size needs to be calculated based
* on the missing function TEE_BigIntAbs, so we do not port it yet.*/
pub fn is_probable_prime(&self, confidence_level: u32) -> i32 {
unsafe { raw::TEE_BigIntIsProbablePrime(self.data_ptr(), confidence_level) }
}
pub fn convert_from_big_int_fmm(
&mut self,
src: &BigIntFMM,
n: &BigInt,
context: BigIntFMMContext,
) {
unsafe {
raw::TEE_BigIntConvertToFMM(
self.0.as_mut_ptr(),
src.data_ptr(),
n.data_ptr(),
context.data_ptr(),
)
};
}
}
impl fmt::Display for BigInt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x?}", self.0)
}
}
pub struct BigIntFMMContext(Vec<BigIntFMMContextUnit>);
impl BigIntFMMContext {
pub fn data_ptr(&self) -> *const u32 {
self.0.as_ptr()
}
fn size_in_u32(size: usize) -> usize {
unsafe { raw::TEE_BigIntFMMContextSizeInU32(size) }
}
// Globalplatform define FMMContext1 here while OP-TEE does not update yet
pub fn new(bits: u32, modulus: BigInt) -> Result<Self> {
let size: usize = Self::size_in_u32(bits as usize) as usize;
let mut tmp_vec: Vec<BigIntFMMContextUnit> = vec![0; size];
unsafe {
raw::TEE_BigIntInitFMMContext(tmp_vec.as_mut_ptr(), size, modulus.data_ptr())
};
Ok(Self(tmp_vec))
}
}
pub struct BigIntFMM(Vec<BigIntFMMUnit>);
impl BigIntFMM {
pub fn data_ptr(&self) -> *const u32 {
self.0.as_ptr()
}
fn size_in_u32(size: usize) -> usize {
unsafe { raw::TEE_BigIntFMMSizeInU32(size) }
}
pub fn new(bits: u32) -> Self {
let size: usize = Self::size_in_u32(bits as usize) as usize;
let mut tmp_vec: Vec<BigIntFMMUnit> = vec![0; size];
unsafe { raw::TEE_BigIntInitFMM(tmp_vec.as_mut_ptr(), size) };
Self(tmp_vec)
}
//Has to be initialized first
pub fn convert_from_big_int(&mut self, src: &BigInt, n: &BigInt, context: BigIntFMMContext) {
unsafe {
raw::TEE_BigIntConvertToFMM(
self.0.as_mut_ptr(),
src.data_ptr(),
n.data_ptr(),
context.data_ptr(),
)
};
}
//Has to be initialized first
pub fn compute_fmm(
&mut self,
op1: &BigIntFMM,
op2: &BigIntFMM,
n: &BigInt,
context: BigIntFMMContext,
) {
unsafe {
raw::TEE_BigIntComputeFMM(
self.0.as_mut_ptr(),
op1.data_ptr(),
op2.data_ptr(),
n.data_ptr(),
context.data_ptr(),
)
};
}
}
//OP-TEE in version GP 1.1.1 does not implement function:
//TEE_BigIntSetBit
//TEE_BigIntAssign
//TEE_BigIntAbs
//TEE_BigIntExpMod