Skip to content

Commit

Permalink
Change ed19 to work with arbitrary-length messages (#795)
Browse files Browse the repository at this point in the history
* Add blob tx

* Add some tests

* Add opcodes for blob storage access

* Freeze stack on DLDC instead of copying it over the data

* Add internal context test cases

* Add changelog entry

* Remove bldc. Allow executable stack.

* Merge RunResult helper type with AluResult

* Move blob tx data to witness like other txs do

* Fixes for fuel-core

* Merge RunResult types after branch merge

* Fix no_std imports

* Add blob id validation rule

* Add base_asset_id to blob::CheckedMetadata

* Use LDC with mode argument instead of having separate blob instructions

* Restore BSIZ and BLDD instructions

* fmt

* Update doc comment (PR feedback)

* Improve test case names (pr feedback)

* Apply PR review suggestions

* Fix the serialization for the blob

* Fix the serialization for the blob

* Make clippy happy

* Add offset and encoding tests

* Add as_blob(_mut) for tx

* fix clippy

* Preparation for the `ed19` modifications

* Updated CHANGELOG.md

* Updated comment

* Actually implement the opcode changes

* Update changelog

* Change the gas cost approximation

* Fix some tests (PR comments)

* Add a test case for zero length mapping to 32

* Remove extra code added in merge

* Fix more issues of merge

* And even more

* I though I already removed this one

* Add couple more test cases

* Fix no_std imports for tests

* Remove more incorrect merge changes

* Rename and clean up crypto opcode unit tests

* Fix typo in cfg

---------

Co-authored-by: Hannes Karppila <hannes.karppila@gmail.com>
Co-authored-by: Hannes Karppila <2204863+Dentosal@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 27, 2024
1 parent d2c76e2 commit 1bf892d
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 101 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

#### Breaking
- [#780](https://github.com/FuelLabs/fuel-vm/pull/780): Added `Blob` transaction, and `BSIZ` and `BLDD` instructions. Also allows `LDC` to load blobs.
- [#795](https://github.com/FuelLabs/fuel-vm/pull/795): Fixed `ed19` instruction to take variable length message instead of a fixed-length one. Changed the gas cost to be `DependentCost`.

## [Version 0.55.0]

Expand Down
8 changes: 4 additions & 4 deletions fuel-asm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,12 @@ impl_instructions! {
0x3C TR tr [contract_id_addr: RegId amount: RegId asset_id_addr: RegId]
"Transfer coins to a variable output."
0x3D TRO tro [contract_id_addr: RegId output_index: RegId amount: RegId asset_id_addr: RegId]
"The 64-byte public key (x, y) recovered from 64-byte signature on 32-byte message."
"The 64-byte public key (x, y) recovered from 64-byte signature on 32-byte message hash."
0x3E ECK1 eck1 [dst_addr: RegId sig_addr: RegId msg_hash_addr: RegId]
"The 64-byte Secp256r1 public key (x, y) recovered from 64-byte signature on 32-byte message."
"The 64-byte Secp256r1 public key (x, y) recovered from 64-byte signature on 32-byte message hash."
0x3F ECR1 ecr1 [dst_addr: RegId sig_addr: RegId msg_hash_addr: RegId]
"Verify ED25519 public key and signature match a 32-byte message."
0x40 ED19 ed19 [pub_key_addr: RegId sig_addr: RegId msg_hash_addr: RegId]
"Verify ED25519 public key and signature match a message."
0x40 ED19 ed19 [pub_key_addr: RegId sig_addr: RegId msg_addr: RegId msg_len: RegId]
"The keccak-256 hash of a slice."
0x41 K256 k256 [dst_addr: RegId src_addr: RegId len: RegId]
"The SHA-2-256 hash of a slice."
Expand Down
9 changes: 3 additions & 6 deletions fuel-crypto/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,20 @@ use fuel_types::{
Bytes64,
};

use crate::{
message::Message,
Error,
};
use crate::Error;

/// Verify a signature against a message digest and a public key.
pub fn verify(
pub_key: &Bytes32,
signature: &Bytes64,
message: &Message,
message: &[u8],
) -> Result<(), Error> {
let signature = Signature::from_bytes(signature);

let pub_key = ed25519_dalek::VerifyingKey::from_bytes(pub_key)
.map_err(|_| Error::InvalidPublicKey)?;

if pub_key.verify_strict(&**message, &signature).is_ok() {
if pub_key.verify_strict(message, &signature).is_ok() {
Ok(())
} else {
Err(Error::InvalidSignature)
Expand Down
34 changes: 22 additions & 12 deletions fuel-tx/src/transaction/consensus_parameters/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,6 @@ impl GasCostsValues {
}
}

pub fn ed19(&self) -> Word {
match self {
GasCostsValues::V1(v1) => v1.ed19,
GasCostsValues::V2(v2) => v2.ed19,
GasCostsValues::V3(v3) => v3.ed19,
GasCostsValues::V4(v4) => v4.ed19,
}
}

pub fn eq_(&self) -> Word {
match self {
GasCostsValues::V1(v1) => v1.eq,
Expand Down Expand Up @@ -945,6 +936,24 @@ impl GasCostsValues {
}
}

pub fn ed19(&self) -> DependentCost {
match self {
GasCostsValues::V1(v1) => DependentCost::HeavyOperation {
base: v1.ed19,
gas_per_unit: 0,
},
GasCostsValues::V2(v2) => DependentCost::HeavyOperation {
base: v2.ed19,
gas_per_unit: 0,
},
GasCostsValues::V3(v3) => DependentCost::HeavyOperation {
base: v3.ed19,
gas_per_unit: 0,
},
GasCostsValues::V4(v4) => v4.ed19,
}
}

pub fn k256(&self) -> DependentCost {
match self {
GasCostsValues::V1(v1) => v1.k256,
Expand Down Expand Up @@ -1513,6 +1522,7 @@ pub struct GasCostsValuesV3 {
/// Gas costs for every op.
/// The difference with [`GasCostsValuesV3`]:
/// - Added `bsiz`, `bldd` instructions
/// - Changed `ed19` to be `DependentCost`
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(default = "GasCostsValuesV4::unit")]
Expand All @@ -1531,7 +1541,6 @@ pub struct GasCostsValuesV4 {
pub divi: Word,
pub eck1: Word,
pub ecr1: Word,
pub ed19: Word,
pub eq: Word,
pub exp: Word,
pub expi: Word,
Expand Down Expand Up @@ -1618,6 +1627,7 @@ pub struct GasCostsValuesV4 {
pub ccp: DependentCost,
pub croo: DependentCost,
pub csiz: DependentCost,
pub ed19: DependentCost,
pub k256: DependentCost,
pub ldc: DependentCost,
pub logd: DependentCost,
Expand Down Expand Up @@ -2428,7 +2438,6 @@ impl GasCostsValuesV4 {
divi: 0,
eck1: 0,
ecr1: 0,
ed19: 0,
eq: 0,
exp: 0,
expi: 0,
Expand Down Expand Up @@ -2509,6 +2518,7 @@ impl GasCostsValuesV4 {
ccp: DependentCost::free(),
croo: DependentCost::free(),
csiz: DependentCost::free(),
ed19: DependentCost::free(),
k256: DependentCost::free(),
ldc: DependentCost::free(),
logd: DependentCost::free(),
Expand Down Expand Up @@ -2549,7 +2559,6 @@ impl GasCostsValuesV4 {
divi: 1,
eck1: 1,
ecr1: 1,
ed19: 1,
eq: 1,
exp: 1,
expi: 1,
Expand Down Expand Up @@ -2630,6 +2639,7 @@ impl GasCostsValuesV4 {
ccp: DependentCost::unit(),
croo: DependentCost::unit(),
csiz: DependentCost::unit(),
ed19: DependentCost::unit(),
k256: DependentCost::unit(),
ldc: DependentCost::unit(),
logd: DependentCost::unit(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pub fn default_gas_costs() -> GasCostsValues {
divi: 1,
eck1: 951,
ecr1: 3000,
ed19: 3000,
eq: 1,
exp: 1,
expi: 1,
Expand Down Expand Up @@ -102,6 +101,10 @@ pub fn default_gas_costs() -> GasCostsValues {
base: 2,
units_per_gas: 214,
},
ed19: DependentCost::LightOperation {
base: 3000,
units_per_gas: 214,
},
k256: DependentCost::LightOperation {
base: 11,
units_per_gas: 214,
Expand Down
9 changes: 5 additions & 4 deletions fuel-vm/src/interpreter/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ where
a: Word,
b: Word,
c: Word,
len: Word,
) -> SimpleResult<()> {
let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
ed25519_verify(self.memory.as_mut(), err, pc, a, b, c)
ed25519_verify(self.memory.as_mut(), err, pc, a, b, c, len)
}

pub(crate) fn keccak256(&mut self, a: Word, b: Word, c: Word) -> SimpleResult<()> {
Expand Down Expand Up @@ -155,13 +156,13 @@ pub(crate) fn ed25519_verify(
a: Word,
b: Word,
c: Word,
len: Word,
) -> SimpleResult<()> {
let pub_key = Bytes32::from(memory.read_bytes(a)?);
let sig = Bytes64::from(memory.read_bytes(b)?);
let msg = Bytes32::from(memory.read_bytes(c)?);
let message = Message::from_bytes_ref(&msg);
let msg = memory.read(c, len)?;

if fuel_crypto::ed25519::verify(&pub_key, &sig, message).is_ok() {
if fuel_crypto::ed25519::verify(&pub_key, &sig, msg).is_ok() {
clear_err(err);
} else {
set_err(err);
Expand Down
19 changes: 11 additions & 8 deletions fuel-vm/src/interpreter/crypto/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use alloc::vec;
use fuel_crypto::SecretKey;
use rand::{
rngs::StdRng,
RngCore,
SeedableRng,
};

Expand Down Expand Up @@ -110,21 +111,22 @@ fn test_verify_ed25519() -> SimpleResult<()> {
let mut err = 0;
let mut pc = 4;

let sig_address = 0;
let msg_address = 64;
let pubkey_address = 64 + 32;
let pubkey_address = 0;
let sig_address = pubkey_address + 32;
let msg_address = sig_address + 64;

let mut rng = rand::rngs::OsRng;
let signing_key = ed25519_dalek::SigningKey::generate(&mut rng);

let message = Message::new([3u8; 100]);
let signature = signing_key.sign(&*message);
let mut message = [0u8; 100];
rng.fill_bytes(&mut message);
let signature = signing_key.sign(&message);

memory[sig_address..sig_address + Signature::LEN]
.copy_from_slice(&signature.to_bytes());
memory[msg_address..msg_address + Message::LEN].copy_from_slice(message.as_ref());
memory[pubkey_address..pubkey_address + Bytes32::LEN]
.copy_from_slice(signing_key.verifying_key().as_ref());
memory[sig_address..sig_address + Signature::LEN]
.copy_from_slice(&signature.to_bytes());
memory[msg_address..msg_address + message.len()].copy_from_slice(message.as_ref());

ed25519_verify(
&mut memory,
Expand All @@ -133,6 +135,7 @@ fn test_verify_ed25519() -> SimpleResult<()> {
pubkey_address as Word,
sig_address as Word,
msg_address as Word,
message.len() as Word,
)?;
assert_eq!(pc, 8);
assert_eq!(err, 0);
Expand Down
13 changes: 10 additions & 3 deletions fuel-vm/src/interpreter/executors/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,9 +845,16 @@ where
}

Instruction::ED19(ed19) => {
self.gas_charge(self.gas_costs().ed19())?;
let (a, b, c) = ed19.unpack();
self.ed25519_verify(r!(a), r!(b), r!(c))?;
let (a, b, c, len) = ed19.unpack();
let mut len = r!(len);

// Backwards compatibility with old contracts
if len == 0 {
len = 32;
}

self.dependent_gas_charge(self.gas_costs().ed19(), len)?;
self.ed25519_verify(r!(a), r!(b), r!(c), len)?;
}

Instruction::K256(k256) => {
Expand Down
Loading

0 comments on commit 1bf892d

Please sign in to comment.