Add mina library with poseidon

This commit is contained in:
Martin Ondejka 2023-04-05 21:48:30 +02:00
parent e5eb32acee
commit 37b5a40ab8
5 changed files with 1353 additions and 0 deletions

1182
mina/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

17
mina/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "mina"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["staticlib"]
[dependencies]
mina-hasher = { git = "https://github.com/o1-labs/proof-systems", tag = "0.1.0", version = "0.1.0" }
mina-signer = { git = "https://github.com/o1-labs/proof-systems", tag = "0.1.0", version = "0.1.0" }
o1-utils = { git = "https://github.com/o1-labs/proof-systems", tag = "0.1.0", version = "0.1.0" }
[build-dependencies]
cbindgen = "0.24.3"

35
mina/build.rs Normal file
View file

@ -0,0 +1,35 @@
extern crate cbindgen;
use cbindgen::Config;
use std::env;
use std::path::PathBuf;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let package_name = env::var("CARGO_PKG_NAME").unwrap();
let output_file = target_dir()
.join(format!("{}.h", package_name))
.display()
.to_string();
let config = Config {
language: cbindgen::Language::C,
..Default::default()
};
cbindgen::generate_with_config(&crate_dir, config)
.unwrap()
.write_to_file(&output_file);
}
/// Find the location of the `target/` directory. Note that this may be
/// overridden by `cmake`, so we also need to check the `CARGO_TARGET_DIR`
/// variable.
fn target_dir() -> PathBuf {
if let Ok(target) = env::var("CARGO_TARGET_DIR") {
PathBuf::from(target)
} else {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("target")
}
}

56
mina/src/lib.rs Normal file
View file

@ -0,0 +1,56 @@
mod mina;
use std::array::TryFromSliceError;
use mina::{Message, NetworkId};
use mina_signer::{BaseField, CurvePoint, PubKey, Signature, ScalarField};
use o1_utils::FieldHelpers;
pub const FIELD_SIZE: usize = 32;
#[no_mangle]
pub extern "C" fn poseidon_hash(
network_id: u8,
field_ptr: *const u8,
field_len: usize,
output_ptr: *mut u8, // 32 bytes
) -> bool {
let network_id = match network_id {
0x00 => NetworkId::TESTNET,
0x01 => NetworkId::MAINNET,
0xff => NetworkId::NULLNET,
_ => return false,
};
let fields = unsafe { std::slice::from_raw_parts(field_ptr, field_len * FIELD_SIZE) };
let fields = match fields
.chunks(FIELD_SIZE)
.map(|chunk| chunk[..32].try_into())
.collect::<Result<Vec<[u8; 32]>, TryFromSliceError>>()
{
Ok(fields) => fields,
Err(_) => return false,
};
let msg = match Message::from_bytes_slice(&fields) {
Ok(msg) => msg,
Err(_) => return false,
};
let hash = mina::poseidon(&msg, network_id);
let output = unsafe { std::slice::from_raw_parts_mut(output_ptr, FIELD_SIZE) };
output.copy_from_slice(&hash.to_bytes());
true
}
#[cfg(test)]
mod tests {
// use super::*;
#[test]
fn it_works() {}
}

63
mina/src/mina.rs Normal file
View file

@ -0,0 +1,63 @@
use mina_hasher::{DomainParameter, Hashable, Hasher, ROInput};
use mina_signer::{BaseField, PubKey, Signer, Signature};
use o1_utils::{field_helpers::FieldHelpersError, FieldHelpers};
#[derive(Debug, Clone)]
#[repr(C)]
pub enum NetworkId {
TESTNET = 0x00,
MAINNET = 0x01,
NULLNET = 0xff,
}
impl From<NetworkId> for u8 {
fn from(id: NetworkId) -> u8 {
id as u8
}
}
impl DomainParameter for NetworkId {
fn into_bytes(self) -> Vec<u8> {
vec![self as u8]
}
}
#[derive(Clone)]
pub struct Message {
fields: Vec<BaseField>,
}
impl Message {
pub fn from_bytes_slice(fields_bytes: &[[u8; 32]]) -> Result<Self, FieldHelpersError> {
Ok(Self {
fields: fields_bytes
.iter()
.map(|bytes| BaseField::from_bytes(bytes))
.collect::<Result<Vec<BaseField>, FieldHelpersError>>()?,
})
}
}
impl Hashable for Message {
type D = NetworkId;
fn to_roinput(&self) -> ROInput {
self.fields
.iter()
.fold(ROInput::new(), |roi, field| roi.append_field(*field))
}
fn domain_string(network_id: NetworkId) -> Option<String> {
match network_id {
NetworkId::MAINNET => "MinaSignatureMainnet".to_string().into(),
NetworkId::TESTNET => "CodaSignature".to_string().into(),
NetworkId::NULLNET => None,
}
}
}
pub fn poseidon(msg: &Message, network_id: NetworkId) -> BaseField {
let mut hasher = mina_hasher::create_kimchi::<Message>(network_id);
hasher.hash(msg)
}