lambdaclass/zksync_era_precompiles

Compilation error in`EcPairing`

ColoCarletti opened this issue · 1 comments

Context: EcPairing.yul

Description:
Although in the current state the ecPairing contract compiles, if more functions are added or some are changed, the following compilation error occurs:

assembly-to-bytecode conversion error: assembly parse error Label DEFAULT_UNWIND was tried to be used for either PC or constant at offset 238030 that is more than '65535' addressable space

This error comes from: https://github.com/matter-labs/era-zkEVM-assembly/blob/v1.3.2/src/error.rs#L41

#[derive(Debug, Error, PartialEq)]
pub enum AssemblyParseError {
    [...]
    #[error("Label {1} was tried to be used for either PC or constant at offset {0} that is more than `{2}` addressable space")]
    CodeIsTooLong(usize, String, u64),
}

And it is triggered by one of the following functions: https://github.com/matter-labs/era-zkEVM-assembly/blob/v1.3.2/src/assembly/instruction/mod.rs#L267

pub(crate) fn link_operand<const N: usize, E: VmEncodingMode<N>>(
    operand: &mut FullOperand,
    function_labels_to_pc: &HashMap<String, usize>,
    constant_labels_to_offset: &HashMap<String, usize>,
    globals_to_offsets: &HashMap<String, usize>,
) -> Result<(), AssemblyParseError> {
    match operand.clone() {
        FullOperand::Constant(ConstantOperand {
            label,
            register,
            immediate,
        }) => {
            if let Some(pc) = function_labels_to_pc.get(&*label).copied() {
                assert_eq!(
                    immediate, 0,
                    "jumps can not have immediates in labels addressing"
                );
                assert!(
                    register.is_void(),
                    "jumps can not have registers in labels addressing"
                );
                if pc > (E::PcOrImm::max()).as_u64() as usize {
                    return Err(AssemblyParseError::CodeIsTooLong(
                        pc,
                        label,
                        (E::PcOrImm::max()).as_u64(),
                    ));
                }
                // assert!(pc <= Offset::MAX as usize, "pc overflow in linker");
                *operand = FullOperand::Full(GenericOperand {
                    r#type: ImmMemHandlerFlags::UseImm16Only,
                    register: RegisterOperand::Null,
                    immediate: pc as u64,
                });
            } else if let Some(offset) = constant_labels_to_offset.get(&*label).copied() {
                if offset > (E::PcOrImm::max()).as_u64() as usize {
                    return Err(AssemblyParseError::CodeIsTooLong(
                        offset,
                        label,
                        (E::PcOrImm::max()).as_u64(),
                    ));
                }
                // assert!(offset <= Offset::MAX as usize, "offset overflow in linker");
                let imm = E::PcOrImm::from_u64_clipped(immediate)
                    .wrapping_add(E::PcOrImm::from_u64_clipped(offset as u64))
                    .as_u64();

                *operand = FullOperand::Full(GenericOperand {
                    r#type: ImmMemHandlerFlags::UseCodePage,
                    register,
                    immediate: imm,
                });
            } else {
                return Err(AssemblyParseError::LabelNotFound(label.to_owned()));
            }
        }
        FullOperand::GlobalVariable(GlobalVariable {
            label,
            register,
            immediate,
        }) => {
            if let Some(offset) = globals_to_offsets.get(&*label).copied() {
                if offset > (E::PcOrImm::max()).as_u64() as usize {
                    return Err(AssemblyParseError::CodeIsTooLong(
                        offset,
                        label,
                        (E::PcOrImm::max()).as_u64(),
                    ));
                }
                // assert!(offset <= Offset::MAX as usize, "offset overflow in linker");
                let imm = E::PcOrImm::from_u64_clipped(immediate)
                    .wrapping_add(E::PcOrImm::from_u64_clipped(offset as u64))
                    .as_u64();

                *operand = FullOperand::Full(GenericOperand {
                    r#type: ImmMemHandlerFlags::UseAbsoluteOnStack,
                    register,
                    immediate: imm,
                });
            } else {
                return Err(AssemblyParseError::LabelNotFound(label.to_owned()));
            }
        }
        _ => {}
    }

    Ok(())
}

Steps to reproduce:

  1. Go to this line: EcPairing.yul#L1294
  2. Replace it with: f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121 := fp12Square(f000, f001, f010, f011, f020, f021, f100, f101, f110, f111, f120, f121).
  3. make run.

Can this be closed @ColoCarletti?