iden3 / circom

zkSnark circuit compiler
GNU General Public License v3.0
1.35k stars 267 forks source link

Inconsistent Bitwise Evaluation for Field Prime #288

Closed LukiMueller closed 3 months ago

LukiMueller commented 3 months ago

Hello, I found following weird behavior in circom when working with the bn128 field prime.

template Example() {
    var prime = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    log("prime = ", prime);
    log("prime | 1 =", prime | 1);
    log("prime & 1 =", prime & 1);
}

/**
OUTPUT:

prime =  0
prime | 1 = 0
prime & 1 = 1
*/

It seems that the modulo is only applied after the | and & evaluation. By further playing around with the expressions, I found out that the modulo is only applied if assigned to a signal or used in an arithmetic expression. Following snippets yield expected results:

Arithmetic Example:

template Example() {
    var prime = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
    var prime_plus_zero = prime + 0;

    log("prime_plus_zero = ", prime_plus_zero);
    log("prime_plus_zero | 1 =", prime_plus_zero | 1);
    log("prime_plus_zero & 1 =", prime_plus_zero & 1);
}

/**
OUTPUT:

prime_plus_zero =  0
prime_plus_zero | 1 = 1
prime_plus_zero & 1 = 0
*/

Signal Example:

template Example() {
    signal prime_sig;
    prime_sig <-- 21888242871839275222246405745257275088548364400416034343698204186575808495617;
    log("prime_sig = ", prime_sig);
    log("prime_sig | 1 =", prime_sig | 1);
    log("prime_sig & 1 =", prime_sig & 1);
}

/**
OUTPUT:

prime_plus_zero =  0
prime_plus_zero | 1 = 1
prime_plus_zero & 1 = 0
*/

Finally, the modulo is not applied on conditional expressions if they are constant, but it is applied if the condition is a signal:

Conditional Example:

template Example() {
    signal input a;
    var prime_cond1 = a 
        ? 21888242871839275222246405745257275088548364400416034343698204186575808495617
        : 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    log("prime_cond1 = ", prime_cond1);
    log("prime_cond1 | 1 =", prime_cond1 | 1);
    log("prime_cond1 & 1 =", prime_cond1 & 1);

    var prime_cond2 = 1 
        ? 21888242871839275222246405745257275088548364400416034343698204186575808495617
        : 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    log("prime_cond2 = ", prime_cond2);
    log("prime_cond2 | 1 =", prime_cond2 | 1);
    log("prime_cond2 & 1 =", prime_cond2 & 1);
}

/**
INPUT:

{ "a" : 1 }

OUTPUT:

prime_cond1 =  0
prime_cond1 | 1 = 1
prime_cond1 & 1 = 0
prime_cond2 =  0
prime_cond2 | 1 = 0
prime_cond2 & 1 = 1
*/
miguelis commented 3 months ago

Thank you. Solved!