From 273ffda0563a81e50be8a23ffb6c8e6351a54dc9 Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Thu, 14 Nov 2024 16:56:41 +0100 Subject: [PATCH] Add code for ec add and ec mul --- fuel-asm/src/panic_reason.rs | 5 + fuel-vm/Cargo.toml | 1 + fuel-vm/src/interpreter/crypto.rs | 154 +++++++++++++++++++++++++----- 3 files changed, 134 insertions(+), 26 deletions(-) diff --git a/fuel-asm/src/panic_reason.rs b/fuel-asm/src/panic_reason.rs index 3dc9881c7c..d348c599c5 100644 --- a/fuel-asm/src/panic_reason.rs +++ b/fuel-asm/src/panic_reason.rs @@ -152,6 +152,11 @@ enum_from! { BlobIdAlreadyUploaded = 0x37, /// Active gas costs do not define the cost for this instruction. GasCostNotDefined = 0x38, + /// The curve id is not supported. + UnsupportedCurveId = 0x39, + // TODO: Maybe add more different errors + /// Read alt_bn_128 curve point is invalid. + InvalidAltBn128Point = 0x3a, } } diff --git a/fuel-vm/Cargo.toml b/fuel-vm/Cargo.toml index b6557e7530..c433917ae1 100644 --- a/fuel-vm/Cargo.toml +++ b/fuel-vm/Cargo.toml @@ -20,6 +20,7 @@ anyhow = { version = "1.0", optional = true } async-trait = "0.1" backtrace = { version = "0.3", optional = true } # requires debug symbols to work bitflags = { workspace = true } +bn = { package = "substrate-bn", version = "0.6", default-features = false } derivative = "2.2" derive_more = { version = "0.99", default-features = false, features = [ "display", diff --git a/fuel-vm/src/interpreter/crypto.rs b/fuel-vm/src/interpreter/crypto.rs index 4d133fc278..6341bcb605 100644 --- a/fuel-vm/src/interpreter/crypto.rs +++ b/fuel-vm/src/interpreter/crypto.rs @@ -15,6 +15,13 @@ use crate::{ error::SimpleResult, }; +use bn::{ + AffineG1, + Fq, + Fr, + Group, + G1, +}; use fuel_crypto::{ Hasher, Message, @@ -92,7 +99,13 @@ where ) } - pub(crate) fn ec_add(&mut self, a: Word, b: Word, c: Word, d: Word) -> SimpleResult<()> { + pub(crate) fn ec_add( + &mut self, + a: Word, + b: Word, + c: Word, + d: Word, + ) -> SimpleResult<()> { let owner = self.ownership_registers(); ec_add( self.memory.as_mut(), @@ -105,7 +118,13 @@ where ) } - pub(crate) fn ec_mul(&mut self, a: Word, b: Word, c: Word, d: Word) -> SimpleResult<()> { + pub(crate) fn ec_mul( + &mut self, + a: Word, + b: Word, + c: Word, + d: Word, + ) -> SimpleResult<()> { let owner = self.ownership_registers(); ec_mul( self.memory.as_mut(), @@ -118,7 +137,13 @@ where ) } - pub(crate) fn ec_pairing(&mut self, a: Word, b: Word, c: Word, d: Word) -> SimpleResult<()> { + pub(crate) fn ec_pairing( + &mut self, + a: Word, + b: Word, + c: Word, + d: Word, + ) -> SimpleResult<()> { let owner = self.ownership_registers(); ec_pairing( self.memory.as_mut(), @@ -242,38 +267,115 @@ pub(crate) fn sha256( Ok(inc_pc(pc)?) } +fn read_point_alt_bn_128(memory: &MemoryInstance, point_ptr: Word) -> SimpleResult { + let px = Fq::from_slice(memory.read(point_ptr, 32u64)?).map_err(|_| { + crate::error::PanicOrBug::Panic(fuel_tx::PanicReason::InvalidAltBn128Point) + })?; + let py = Fq::from_slice( + memory.read( + point_ptr + .checked_add(32) + .ok_or(crate::error::PanicOrBug::Panic( + fuel_tx::PanicReason::ArithmeticOverflow, + ))?, + 32u64, + )?, + ) + .map_err(|_| { + crate::error::PanicOrBug::Panic(fuel_tx::PanicReason::InvalidAltBn128Point) + })?; + + if px == Fq::zero() && py == Fq::zero() { + Ok(G1::zero()) + } else { + AffineG1::new(px, py).map(Into::into).map_err(|_| { + crate::error::PanicOrBug::Panic(fuel_tx::PanicReason::InvalidAltBn128Point) + }) + } +} + +// TODO: When regid when imm ? pub(crate) fn ec_add( - _memory: &mut MemoryInstance, - _owner: OwnershipRegisters, - _pc: RegMut, - _a: Word, - _b: Word, - _c: Word, - _d: Word, + memory: &mut MemoryInstance, + owner: OwnershipRegisters, + pc: RegMut, + dst: Word, + curve_id: Word, + point1_ptr: Word, + point2_ptr: Word, ) -> SimpleResult<()> { - todo!() + match curve_id { + 0 => { + let point1 = read_point_alt_bn_128(memory, point1_ptr)?; + let point2 = read_point_alt_bn_128(memory, point2_ptr)?; + let mut output = [0u8; 64]; + #[allow(clippy::arithmetic_side_effects)] + if let Some(sum) = AffineG1::from_jacobian(point1 + point2) { + sum.x().to_big_endian(&mut output[..32]).unwrap(); + sum.y().to_big_endian(&mut output[32..]).unwrap(); + } + memory.write_bytes(owner, dst, output)?; + } + _ => { + return Err(crate::error::PanicOrBug::Panic( + fuel_tx::PanicReason::UnsupportedCurveId, + )) + } + } + Ok(inc_pc(pc)?) } pub(crate) fn ec_mul( - _memory: &mut MemoryInstance, - _owner: OwnershipRegisters, - _pc: RegMut, - _a: Word, - _b: Word, - _c: Word, - _d: Word, + memory: &mut MemoryInstance, + owner: OwnershipRegisters, + pc: RegMut, + dst: Word, + curve_id: Word, + point_ptr: Word, + scalar_ptr: Word, ) -> SimpleResult<()> { - todo!() + match curve_id { + 0 => { + let point = read_point_alt_bn_128(memory, point_ptr)?; + let scalar = + Fr::from_slice(memory.read(scalar_ptr, 32u64)?).map_err(|_| { + crate::error::PanicOrBug::Panic( + fuel_tx::PanicReason::InvalidAltBn128Point, + ) + })?; + let mut output = [0u8; 64]; + #[allow(clippy::arithmetic_side_effects)] + if let Some(product) = AffineG1::from_jacobian(point * scalar) { + product.x().to_big_endian(&mut output[..32]).unwrap(); + product.y().to_big_endian(&mut output[32..]).unwrap(); + } + memory.write_bytes(owner, dst, output)?; + } + _ => { + return Err(crate::error::PanicOrBug::Panic( + fuel_tx::PanicReason::UnsupportedCurveId, + )) + } + } + Ok(inc_pc(pc)?) } pub(crate) fn ec_pairing( _memory: &mut MemoryInstance, _owner: OwnershipRegisters, - _pc: RegMut, - _a: Word, - _b: Word, - _c: Word, - _d: Word, + pc: RegMut, + _success: Word, + curve_id: Word, + _num_points: Word, + _points_ptr: Word, ) -> SimpleResult<()> { - todo!() -} \ No newline at end of file + match curve_id { + 0 => {} + _ => { + return Err(crate::error::PanicOrBug::Panic( + fuel_tx::PanicReason::UnsupportedCurveId, + )) + } + } + Ok(inc_pc(pc)?) +}