cairo-native 0.9.0-rc.3

A compiler to convert Cairo's IR Sierra code to MLIR and execute it.
use starknet::SyscallResultTrait;
use starknet::secp256_trait::{Secp256PointTrait, Signature, is_valid_signature, recover_public_key};
use starknet::secp256r1::{Secp256r1Impl, Secp256r1Point};
use crate::option::OptionTrait;
use crate::test::test_utils::assert_eq;

#[test]
fn test_secp256r1_point_serde() {
    let (x, y): (u256, u256) = (
        0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5,
        0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d,
    );
    let mut serialized_coordinates = array![];
    (x, y).serialize(ref serialized_coordinates);
    let mut serialized_coordinates = serialized_coordinates.span();
    let point = Serde::<Secp256r1Point>::deserialize(ref serialized_coordinates).unwrap();

    let mut actual_coordinates = array![];
    point.serialize(ref actual_coordinates);

    assert_eq!(
        (@x.low.into(), @x.high.into(), @y.low.into(), @y.high.into()),
        (
            actual_coordinates.at(0),
            actual_coordinates.at(1),
            actual_coordinates.at(2),
            actual_coordinates.at(3),
        ),
    );
}

#[test]
fn test_secp256r1_recover_public_key() {
    let (msg_hash, signature, expected_public_key_x, expected_public_key_y, _) =
        get_message_and_signature();
    let public_key = recover_public_key::<Secp256r1Point>(msg_hash, signature).unwrap();
    let (x, y) = public_key.get_coordinates().unwrap_syscall();
    assert(expected_public_key_x == x, 'recover failed 1');
    assert(expected_public_key_y == y, 'recover failed 2');
}


/// Returns a golden valid message hash and its signature, for testing.
fn get_message_and_signature() -> (u256, Signature, u256, u256, Secp256r1Point) {
    // msg = ""
    // public key: (0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5,
    //              0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d)
    let msg_hash = 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855;
    let r = 0xb292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a;
    let s = 0x177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2;

    let (public_key_x, public_key_y) = (
        0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5,
        0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d,
    );

    let public_key = Secp256r1Impl::secp256_ec_new_syscall(public_key_x, public_key_y)
        .unwrap_syscall()
        .unwrap();

    (msg_hash, Signature { r, s, y_parity: true }, public_key_x, public_key_y, public_key)
}

#[test]
#[available_gas(100000000)]
fn test_verify_signature() {
    let (msg_hash, signature, _, _, public_key) = get_message_and_signature();
    let is_valid = is_valid_signature::<
        Secp256r1Point,
    >(msg_hash, signature.r, signature.s, public_key);
    assert(is_valid, 'Signature should be valid');
}

#[test]
#[available_gas(100000000)]
fn test_verify_signature_invalid_signature() {
    let (msg_hash, signature, _, _, public_key) = get_message_and_signature();
    let is_valid = is_valid_signature::<
        Secp256r1Point,
    >(msg_hash, signature.r + 1, signature.s, public_key);
    assert(!is_valid, 'Signature should be invalid');
}

#[test]
#[available_gas(100000000)]
fn test_verify_signature_overflowing_signature_r() {
    let (msg_hash, mut signature, _, _, public_key) = get_message_and_signature();
    let is_valid = is_valid_signature::<
        Secp256r1Point,
    >(msg_hash, Secp256r1Impl::get_curve_size() + 1, signature.s, public_key);
    assert(!is_valid, 'Signature out of range');
}

#[test]
#[available_gas(100000000)]
fn test_verify_signature_overflowing_signature_s() {
    let (msg_hash, mut signature, _, _, public_key) = get_message_and_signature();
    let is_valid = is_valid_signature::<
        Secp256r1Point,
    >(msg_hash, signature.r, Secp256r1Impl::get_curve_size() + 1, public_key);
    assert(!is_valid, 'Signature out of range');
}


#[test]
fn test_recover_public_key_y_even() {
    let x: u256 = 0x502a43ce77c6f5c736a82f847fa95f8c2d483fe223b12b91047d83258a958b0f;
    let _y: u256 = 0xdb0a2e6710c71ba80afeb3abdf69d306ce729c7704f4ddf2eaaf0b76209fe1b0;
    let r: u256 = 0x7380df4a623c5c2259a5e5f5b225d7265a9e24b3a13c101d1afddcf29e3cf8b2;
    let s: u256 = 0x0d131afacdd17a4ea1b544bb3ade677ff8accbe7830e15b9c225e6031155946a;
    let y_parity = false;
    let message_hash: u256 = 0x28c7fff9aef4847a82cd64280434712a5b49205831b60eea6e70614077e672eb;
    let recovered = recover_public_key::<Secp256r1Point>(message_hash, Signature { r, s, y_parity })
        .unwrap();
    let (recovered_x, _recovered_y) = recovered.get_coordinates().unwrap_syscall();

    assert_eq(@recovered_x, @x, 'Signature is not valid');
}