Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust compiler reorders fields in structures #607

Open
khannanov-nil opened this issue May 20, 2024 · 0 comments
Open

Rust compiler reorders fields in structures #607

khannanov-nil opened this issue May 20, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@khannanov-nil
Copy link

Describe the bug
Whenever custom types (e.g., structs) are used in a Rust circuit, there is a possibility that the Rust compiler will reorder fields in these types when producing the circuit IR. When assigner is later called on the IR, it will fail because the order of fields in the public inputs file does not match the order of fields in the IR. There are two solutions to this: reorder fields in the IR manually or use the #[repr(C)] directive before a struct. Both solutions are not so great in terms of dev exp.

To Reproduce
Use cargo to compile this circuit:

#![no_main]

use std::intrinsics::assigner_sha2_256;
use std::intrinsics::assigner_sha2_512;

use ark_curve25519::{EdwardsAffine, Fr};
use ark_pallas::Fq;
use unroll::unroll_for_loops;

type BlockType = [Fq; 2];
type EdDSAMessageBlockType = [Fq; 4];

#[derive(Copy, Clone)]
pub struct BlockDataType {
    prev_block_hash: BlockType,
    data: BlockType,
    validators_signatures: [EdDSASignatureType; 4],
    validators_keys: [EdwardsAffine; 4],
}

#[derive(Copy, Clone)]
pub struct EdDSASignatureType {
    r: EdwardsAffine,
    s: Fr,
}

pub fn hash_512(r: EdwardsAffine, pk: EdwardsAffine, m: EdDSAMessageBlockType) -> Fr {
    assigner_sha2_512(r.0, pk.0, [m[0].0, m[1].0, m[2].0, m[3].0]).into()
}

pub fn hash_256(block1: BlockType, block2: BlockType) -> BlockType {
    let sha = assigner_sha2_256([block1[0].0, block1[1].0], [block2[0].0, block2[1].0]);
    [sha[0].into(), sha[1].into()]
}

pub fn verify_eddsa_signature(
    input: EdDSASignatureType,
    pk: EdwardsAffine,
    m: EdDSAMessageBlockType,
) -> bool {
    let b = EdwardsAffine::one();
    let k = hash_512(input.r, pk, m);
    b * input.s == input.r + (pk * k)
}

pub fn is_same(x: BlockType, y: BlockType) -> bool {
    x[0] == y[0] && x[1] == y[1]
}

#[unroll_for_loops]
pub fn verify_signature(unconfirmed_block: BlockDataType) -> bool {
    let mut is_verified: bool = true;
    let message: EdDSAMessageBlockType = [
        unconfirmed_block.prev_block_hash[0],
        unconfirmed_block.prev_block_hash[1],
        unconfirmed_block.data[0],
        unconfirmed_block.data[1],
    ];

    for i in 0..4 {
        is_verified = is_verified
            && verify_eddsa_signature(
                unconfirmed_block.validators_signatures[i],
                unconfirmed_block.validators_keys[i],
                message,
            );
    }

    is_verified
}

#[circuit]
#[unroll_for_loops]
pub fn verify_protocol_state_proof(
    last_confirmed_block_hash: BlockType,
    unconfirmed_blocks: [BlockDataType; 2],
) -> bool {
    let mut is_correct = is_same(
        unconfirmed_blocks[0].prev_block_hash,
        last_confirmed_block_hash,
    );
    is_correct = is_correct && verify_signature(unconfirmed_blocks[0]);

    for i in 1..2 {
        let evaluated_block_hash: BlockType = hash_256(
            unconfirmed_blocks[i - 1].prev_block_hash,
            unconfirmed_blocks[i - 1].data,
        );

        is_correct =
            is_correct && is_same(unconfirmed_blocks[i].prev_block_hash, evaluated_block_hash);
        is_correct = is_correct && verify_signature(unconfirmed_blocks[i]);
    }

    is_correct
}

Then call assigner with this inputs file.

[
    {
        "array": [
            {"field": "1"},
            {"field": "1"}
        ]
    },
    {
        "array": [
            {
                "struct": [
                    {
                        "array": [
                            {"field": 1},
                            {"field": 1}
                        ]
                    },
                    {
                        "array": [
                            {"field": 3},
                            {"field": 1}
                        ]
                    },
                    {
                        "array": [
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]}
                        ]
                    },
                    {
                        "array": [
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]}
                        ]
                    }
                ]
            },
            {
                "struct": [
                    {
                        "array": [
                            {"field": 1},
                            {"field": 1}
                        ]
                    },
                    {
                        "array": [
                            {"field": 1},
                            {"field": 1}
                        ]
                    },
                    {
                        "array": [
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]},
                            {"struct": [{"curve": [4, 5]}, {"field": 8}]}
                        ]
                    },
                    {
                        "array": [
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]},
                            {"curve": ["0x4f043d481c8f09de646b1aa05de7ebfab126fc8bbb74f42532378c4dec6e76ec", "0x58719b60b26bd8b8b76de1a886ed82aa11692b4dc5494fe96d5b31f1c63f36a8"]}
                        ]
                    }
                ]
            }
        ]
    }
]

Expected behavior
The compiler does NOT reorder fields in structs when producing an IR.

Toolchain versions
rustc 1.73.0-nightly (a516bc539 2023-12-14) (zkLLVM 0.1.18)
0.1.18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant