Skip to content

Commit

Permalink
add new operators to avoid pedersen commitments in amount checks
Browse files Browse the repository at this point in the history
  • Loading branch information
St333p committed Sep 30, 2024
1 parent 7ae9760 commit 0f1b25e
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/vm/macroasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ macro_rules! isa_instr {
(pcvs $no:ident) => {{ RgbIsa::Contract(ContractOp::Pcvs($no)) }};
(pcas $no:ident) => {{ RgbIsa::Contract(ContractOp::Pcas($no)) }};
(pcps $no:ident) => {{ RgbIsa::Contract(ContractOp::Pcps($no)) }};
(svs $no:ident) => {{ RgbIsa::Contract(ContractOp::Svs($no)) }};
(sas $no:ident) => {{ RgbIsa::Contract(ContractOp::Sas($no)) }};
(sps $no:ident) => {{ RgbIsa::Contract(ContractOp::Sps($no)) }};
(cng $t:ident,a8[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnG($t, Reg32::from(u5::with($a_idx)))) }};
(cnc $t:ident,a16[$a_idx:literal]) => {{ RgbIsa::Contract(ContractOp::CnC($t, Reg32::from(u5::with($a_idx)))) }};
(ldm $t:ident,s16[$s_idx:literal]) => {{ RgbIsa::Contract(ContractOp::LdM($t, RegS::from($s_idx))) }};
Expand Down
148 changes: 145 additions & 3 deletions src/vm/op_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,43 @@ pub enum ContractOp<S: ContractStateAccess> {
#[display("ldm {0},{1}")]
LdM(MetaType, RegS),

/// Verify sum of inputs and outputs are equal.
///
/// The only argument specifies owned state type for the sum operation. If
/// this state does not exist, or either inputs or outputs does not have
/// any data for the state, the verification fails.
///
/// If verification succeeds, doesn't change `st0` value; otherwise sets it
/// to `false` and stops execution.
#[display("svs {0}")]
Svs(AssignmentType),

/// Verify sum of outputs and value in `a64[0]` register are equal.
///
/// The first argument specifies owned state type for the sum operation. If
/// this state does not exist, or either inputs or outputs does not have
/// any data for the state, the verification fails.
///
/// If `a64[0]` register does not contain value, the verification fails.
///
/// If verification succeeds, doesn't change `st0` value; otherwise sets it
/// to `false` and stops execution.
#[display("sas {0}")]
Sas(/** owned state type */ AssignmentType),

/// Verify sum of inputs and value in `a64[0]` register are equal.
///
/// The first argument specifies owned state type for the sum operation. If
/// this state does not exist, or either inputs or outputs does not have
/// any data for the state, the verification fails.
///
/// If `a64[0]` register does not contain value, the verification fails.
///
/// If verification succeeds, doesn't change `st0` value; otherwise sets it
/// to `false` and stops execution.
#[display("sps {0}")]
Sps(/** owned state type */ AssignmentType),

/// Verify sum of pedersen commitments from inputs and outputs.
///
/// The only argument specifies owned state type for the sum operation. If
Expand Down Expand Up @@ -202,6 +239,8 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
| ContractOp::LdM(_, _) => bset![],
ContractOp::Pcvs(_) => bset![],
ContractOp::Pcas(_) | ContractOp::Pcps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)],
ContractOp::Svs(_) => bset![],
ContractOp::Sas(_) | ContractOp::Sps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)],

Check warning on line 243 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L242-L243

Added lines #L242 - L243 were not covered by tests
ContractOp::Fail(_, _) => bset![],
}
}
Expand All @@ -227,6 +266,9 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
ContractOp::Pcvs(_) | ContractOp::Pcas(_) | ContractOp::Pcps(_) => {
bset![]
}
ContractOp::Svs(_) | ContractOp::Sas(_) | ContractOp::Sps(_) => {
bset![]

Check warning on line 270 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L270

Added line #L270 was not covered by tests
}
ContractOp::Fail(_, _) => bset![],
}
}
Expand All @@ -243,6 +285,10 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
| ContractOp::LdG(_, _, _)
| ContractOp::LdC(_, _, _) => 8,
ContractOp::LdM(_, _) => 6,
// TODO: what are the proper values for complexity?
ContractOp::Svs(_)
| ContractOp::Sas(_)
| ContractOp::Sps(_) => 20,

Check warning on line 291 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L291

Added line #L291 was not covered by tests
ContractOp::Pcvs(_) => 1024,
ContractOp::Pcas(_) | ContractOp::Pcps(_) => 512,
ContractOp::Fail(_, _) => u64::MAX,
Expand Down Expand Up @@ -286,6 +332,38 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
}
}};
}
macro_rules! load_revealed_inputs {
($state_type:ident) => {{
let Some(prev_state) = context.op_info.prev_state.get($state_type) else {
fail!()
};
match prev_state {
TypedAssigns::Fungible(state) => state
.iter()
.map(Assign::as_revealed_state)
// TODO: properly fail if we can't read revealed state
.map(|s| s.unwrap().value.as_u64())

Check warning on line 345 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L345

Added line #L345 was not covered by tests
.collect::<Vec<_>>(),
_ => fail!(),
}
}};
}
macro_rules! load_revealed_outputs {
($state_type:ident) => {{
let Some(new_state) = context.op_info.owned_state.get(*$state_type) else {
fail!()
};
match new_state {
TypedAssigns::Fungible(state) => state
.iter()
.map(Assign::as_revealed_state)
// TODO: properly fail if we can't read revealed state
.map(|s| s.unwrap().value.as_u64())

Check warning on line 361 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L361

Added line #L361 was not covered by tests
.collect::<Vec<_>>(),
_ => fail!(),
}
}};
}

match self {
ContractOp::CnP(state_type, reg) => {
Expand Down Expand Up @@ -473,6 +551,59 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
fail!()
}
}
ContractOp::Svs(state_type) => {
let Some(input_amt) = load_revealed_inputs!(state_type)
.iter()
.try_fold(0u64, |acc, &x| acc.checked_add(x))

Check warning on line 557 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L554-L557

Added lines #L554 - L557 were not covered by tests
else {
fail!()

Check warning on line 559 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L559

Added line #L559 was not covered by tests
};
let Some(output_amt) = load_revealed_outputs!(state_type)
.iter()
.try_fold(0u64, |acc, &x| acc.checked_add(x))

Check warning on line 563 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L561-L563

Added lines #L561 - L563 were not covered by tests
else {
fail!()

Check warning on line 565 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L565

Added line #L565 was not covered by tests
};
if input_amt != output_amt {
fail!()
}

Check warning on line 569 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L567-L569

Added lines #L567 - L569 were not covered by tests
}

ContractOp::Sas(owned_state) => {
let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else {
fail!()

Check warning on line 574 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L572-L574

Added lines #L572 - L574 were not covered by tests
};
let sum = u64::from(sum);

Check warning on line 576 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L576

Added line #L576 was not covered by tests

let Some(output_amt) = load_revealed_outputs!(owned_state)
.iter()
.try_fold(0u64, |acc, &x| acc.checked_add(x))

Check warning on line 580 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L578-L580

Added lines #L578 - L580 were not covered by tests
else {
fail!()

Check warning on line 582 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L582

Added line #L582 was not covered by tests
};

if sum != output_amt {
fail!()
}

Check warning on line 587 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L585-L587

Added lines #L585 - L587 were not covered by tests
}

ContractOp::Sps(owned_state) => {
let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else {
fail!()

Check warning on line 592 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L590-L592

Added lines #L590 - L592 were not covered by tests
};
let sum = u64::from(sum);

Check warning on line 594 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L594

Added line #L594 was not covered by tests

let Some(input_amt) = load_revealed_inputs!(owned_state)
.iter()
.try_fold(0u64, |acc, &x| acc.checked_add(x))

Check warning on line 598 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L596-L598

Added lines #L596 - L598 were not covered by tests
else {
fail!()

Check warning on line 600 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L600

Added line #L600 was not covered by tests
};

if sum != input_amt {
fail!()
}

Check warning on line 605 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L603-L605

Added lines #L603 - L605 were not covered by tests
}
// All other future unsupported operations, which must set `st0` to `false`.
_ => fail!(),
}
Expand Down Expand Up @@ -501,6 +632,10 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
ContractOp::Pcas(_) => INSTR_PCAS,
ContractOp::Pcps(_) => INSTR_PCPS,

ContractOp::Svs(_) => INSTR_SVS,
ContractOp::Sas(_) => INSTR_SAS,
ContractOp::Sps(_) => INSTR_SPS,

Check warning on line 637 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L635-L637

Added lines #L635 - L637 were not covered by tests

ContractOp::Fail(other, _) => *other,
}
}
Expand Down Expand Up @@ -559,9 +694,12 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
writer.write_u4(u4::ZERO)?;
}

ContractOp::Pcvs(state_type) => writer.write_u16(*state_type)?,
ContractOp::Pcas(owned_type) => writer.write_u16(*owned_type)?,
ContractOp::Pcps(owned_type) => writer.write_u16(*owned_type)?,
ContractOp::Pcvs(state_type)
| ContractOp::Svs(state_type) => writer.write_u16(*state_type)?,
ContractOp::Pcas(owned_type)
| ContractOp::Sas(owned_type) => writer.write_u16(*owned_type)?,
ContractOp::Pcps(owned_type)
| ContractOp::Sps(owned_type) => writer.write_u16(*owned_type)?,

Check warning on line 702 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L697-L702

Added lines #L697 - L702 were not covered by tests

ContractOp::Fail(_, _) => {}
}
Expand Down Expand Up @@ -630,6 +768,10 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
INSTR_PCAS => Self::Pcas(reader.read_u16()?.into()),
INSTR_PCPS => Self::Pcps(reader.read_u16()?.into()),

INSTR_SVS => Self::Svs(reader.read_u16()?.into()),
INSTR_SAS => Self::Sas(reader.read_u16()?.into()),
INSTR_SPS => Self::Sps(reader.read_u16()?.into()),

Check warning on line 773 in src/vm/op_contract.rs

View check run for this annotation

Codecov / codecov/patch

src/vm/op_contract.rs#L771-L773

Added lines #L771 - L773 were not covered by tests

x => Self::Fail(x, PhantomData),
})
}
Expand Down
5 changes: 4 additions & 1 deletion src/vm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,11 @@ pub const INSTR_PCVS: u8 = 0b11_010_000;
pub const INSTR_PCAS: u8 = 0b11_010_001;
pub const INSTR_PCPS: u8 = 0b11_010_010;
// Reserved 0b11_010_011
pub const INSTR_SVS: u8 = 0b11_010_100;
pub const INSTR_SAS: u8 = 0b11_010_101;
pub const INSTR_SPS: u8 = 0b11_010_110;
pub const INSTR_CONTRACT_FROM: u8 = 0b11_000_000;
pub const INSTR_CONTRACT_TO: u8 = 0b11_010_011;
pub const INSTR_CONTRACT_TO: u8 = 0b11_011_011;

// TIMECHAIN:
pub const INSTR_TIMECHAIN_FROM: u8 = 0b11_011_100;
Expand Down

0 comments on commit 0f1b25e

Please sign in to comment.