RGB-WG / rgb-core

RGB Core Library: consensus validation for private & scalable client-validated smart contracts on Bitcoin & Lightning
https://spec.rgb.tech
Apache License 2.0
207 stars 50 forks source link

Confidential value equality fails due to bulletproof noise #214

Closed zoedberg closed 9 months ago

zoedberg commented 9 months ago

I'm not sure this is a bug, but loading the same consignment file twice produces 2 consignments which look identical when formatted in debug but fail equal assertion.

To reproduce this I've done the following:

let bindle_1 = Bindle::<Transfer>::load_file(file)?;
let transfer_1: Transfer = bindle_1.unbindle();

let bindle_2 = Bindle::<Transfer>::load_file(file)?;
let transfer_2: Transfer = bindle_2.unbindle();

assert_eq!(transfer_1, transfer_2);  // this fails

Investigating this I understood the reason is that the PartialEq implementation of the Assign object

impl<State: ExposedState, Seal: ExposedSeal> PartialEq for Assign<State, Seal> {
    fn eq(&self, other: &Self) -> bool {
        self.to_confidential_seal() == other.to_confidential_seal() &&
            self.to_confidential_state() == other.to_confidential_state()
    }
}

returns false. More specifically the calls to to_confidential_seal produce 2 equal values, but the calls to to_confidential_state produce non-deterministic values, for example:

confidential_state_1: ConcealedValue{
  commitment: PedersenCommitment(PedersenCommitment(080a925bab68da6e93521d799f98de0589447261f36132f9d57e349eeab5c8d8e700000000000000000000000000000000000000000000000000000000000000)),
  range_proof: Placeholder(NoiseDumb(Array<512>(1aab472be9ad8ce2ca530a00f6d7e34144955968e3957a432725f03dec32e77b63677bf73fe083d423f5ebd2ba5f1d124a004b6fa1d37cde3a719359910b3f3f6b8021f0baac935f0ab51a0ed80d4e09e885272bd3cf1426b5641b667da2470254e5cdc29de79ce01c6a44ceef44ae568dac1441ac07d28f3bee052afc37afd63af1a487c3d31e5dc990402767d3dec811dd35bdb8ed245437f2225da70ede0f3095946b1ae3728958f26962f19125e725a240e507e047991bad9653f12d2f621c247035a068ce2bdd0f32989003085427a07bf764b0406715aa292db4deb8796eae8d633fdb6763fb25c0be4dc1a5680ea1486fc1dfa3d3018a6329d296ce03350fa3fd9b8695075e66b96fa7b6c9111c920a61b57051b349e80099b0656e58bf6f8ee14ffae9c9146a294e25f48ab90acfe57ae5a9869c52b90d2f14aae391628d20ad7d724a77e3d2c6140e6ad207bb6b944e19d77add94c08ee48264daf8fd8bbab20f7f70e6cd5c985b00574537ec39b11b6ba24ef4c5aff976812db5c0d37a624d08bf80c88e63e1da632f28296c6242a0d9d59475268e96035ca00af5cea06ae2e3326e47e532ac66c525ee0057c02ac7ced97b773fa7d1e6551439eb53ec31fd4adc905907298e478896481edb28c3ee4324fe6ec8cedb63d4197537a9495b983cf787eb27af83e2a3d4535e6f2712229ec9cefc4b791ce0641605d9)))
}

confidential_state_2: ConcealedValue{
  commitment: PedersenCommitment(PedersenCommitment(080a925bab68da6e93521d799f98de0589447261f36132f9d57e349eeab5c8d8e700000000000000000000000000000000000000000000000000000000000000)),
  range_proof: Placeholder(NoiseDumb(Array<512>(28c5411bbbbdb689a81e9f12cc199903bfe342b0a11b8c1785dd82e69461d7d924812b3f0f1ad1ed4db0e125fe5eb801932e4a50dfa98c20c4e4bc31dad4986c22fb1660ff79b178726e86515d3eabbd82a505a548b9fa0c67e61903a1a6259d35cfaef8b974e85774dee4dfe7853e22681857b55db13d81e6e72d1c1ad0f53cce6b32c1eaf2801f62a8f143e5a2773b9bfa4d4d9db1a49a5f9156c9b2a9e1efbcfc6b902a653f07577913a759818a9dfd0ed5c96bad9a9cf341fca0fec0855b75d7cc1354f531f291d59e52b0c537de0d50e2d6c3e61dd0148ab5065e0dee4a3917f9230637c0bad3aa416470a83f61ecdbba28ed206b5550a87348f2103b064324609077958932106d74ba1ff7839b7fa24644fc1e3ffb387a7ecaeab0ad23e5ea6bf4c121d49ec0694d369c1cde9227a1ca281729fd7170debdc0dae31d4f9d954b678f720b5379d7449b30360f427ac501c28318fb7c459569d8db431a57ba905ca1824b18cdb30c9404df1fb7d2ab43217b89392539535f45afc0a1841472234c4c6b0a553347706c969966ee13ff968524a64865aebd569fcfdd296a80fedd8aa7da7758f432ed88ad63a2482e40a2251822a8c3bad36cfe4581b5240ab5c6d6caab5a17998676af75d01f1d4027bca1e92f3aba039ec0824aff9977c113d566e459112bacae4e8c9338be8cdc17e5cfd6c3cd81d346caeba0570bdeef)))
}
dr-orlovsky commented 9 months ago

I also struggle to understand whether this is a bug or a feature... I am open to opinions.

The reason why this happens is a feature of RGB Core, which, until we integrate Bulletproofs, prevents them from being read from the disk, replacing them with random bytes. Why not zeros? To detect cases like that, when we try to use bulletproofs, they will fail. This already saved us from quite a few bugs.

UPD: I probably need to modify PartialEq impl for ConcealedValue, skipping comparing bulletproof data. Anyway this is correct, since we expect bulletproofs to aggregate, and their non-equivalence doesn't imply non-equivalence of the state.