|
| 1 | +use aztec::{ |
| 2 | + hash::compute_public_bytecode_commitment, |
| 3 | + protocol::constants::MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, |
| 4 | +}; |
| 5 | + |
| 6 | +pub(crate) fn validate_packed_public_bytecode( |
| 7 | + packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS], |
| 8 | + public_bytecode_commitment: Field, |
| 9 | +) { |
| 10 | + validate_bytes_encoding(packed_public_bytecode); |
| 11 | + |
| 12 | + assert_eq( |
| 13 | + compute_public_bytecode_commitment(packed_public_bytecode), |
| 14 | + public_bytecode_commitment, |
| 15 | + ); |
| 16 | +} |
| 17 | + |
| 18 | +fn validate_bytes_encoding( |
| 19 | + packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS], |
| 20 | +) { |
| 21 | + // Validate bit size of bytecode length |
| 22 | + packed_public_bytecode[0].assert_max_bit_size::<32>(); |
| 23 | + // 31 bytes per field, the odd upper bits MUST be 0 |
| 24 | + for i in 1..MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { |
| 25 | + packed_public_bytecode[i].assert_max_bit_size::<248>(); |
| 26 | + } |
| 27 | + |
| 28 | + // check that the last field doesn't include garbage after bytes length. |
| 29 | + let bytecode_length_in_bytes = packed_public_bytecode[0] as u32; |
| 30 | + let not_aligned_bytes = bytecode_length_in_bytes % 31; |
| 31 | + |
| 32 | + let bytecode_length_in_fields = |
| 33 | + (bytecode_length_in_bytes / 31) + (not_aligned_bytes != 0) as u32; |
| 34 | + |
| 35 | + // We don't -1 because the first field is the bytes length |
| 36 | + let decomposition: [u8; 32] = packed_public_bytecode[bytecode_length_in_fields].to_be_bytes(); |
| 37 | + |
| 38 | + let expected_populated_bytes = if not_aligned_bytes == 0 { |
| 39 | + 31 |
| 40 | + } else { |
| 41 | + not_aligned_bytes |
| 42 | + }; |
| 43 | + |
| 44 | + let mut should_be_zero = false; |
| 45 | + for i in 0..32 { |
| 46 | + // +1 since we don't check the MSB (since it was already checked by assert_max_bit_size) |
| 47 | + should_be_zero |= i == (expected_populated_bytes + 1); |
| 48 | + |
| 49 | + if should_be_zero { |
| 50 | + assert_eq(decomposition[i], 0, "Extra bytes in the last field of the bytecode"); |
| 51 | + } |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +#[test] |
| 56 | +fn test_validate_bytes_encoding() { |
| 57 | + let mut packed_public_bytecode = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS]; |
| 58 | + packed_public_bytecode[0] = 30; |
| 59 | + // Upper bits clean, no extra trailing bytes |
| 60 | + let bytes = [ |
| 61 | + 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
| 62 | + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, |
| 63 | + 0x1e, 0x00, |
| 64 | + ]; |
| 65 | + packed_public_bytecode[1] = Field::from_be_bytes(bytes); |
| 66 | + |
| 67 | + validate_bytes_encoding(packed_public_bytecode); |
| 68 | +} |
| 69 | + |
| 70 | +#[test(should_fail_with = "assert_max_bit_size")] |
| 71 | +fn test_should_fail_too_large_bytecode_length() { |
| 72 | + let mut packed_public_bytecode = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS]; |
| 73 | + packed_public_bytecode[0] = 0x100000000; |
| 74 | + validate_bytes_encoding(packed_public_bytecode); |
| 75 | +} |
| 76 | + |
| 77 | +#[test(should_fail_with = "assert_max_bit_size")] |
| 78 | +fn test_should_fail_populated_upper_bits() { |
| 79 | + let mut packed_public_bytecode = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS]; |
| 80 | + packed_public_bytecode[0] = 30; |
| 81 | + // one upper bit populated |
| 82 | + let bytes = [ |
| 83 | + 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
| 84 | + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, |
| 85 | + 0x1e, 0x00, |
| 86 | + ]; |
| 87 | + packed_public_bytecode[1] = Field::from_be_bytes(bytes); |
| 88 | + |
| 89 | + validate_bytes_encoding(packed_public_bytecode); |
| 90 | +} |
| 91 | + |
| 92 | +#[test(should_fail_with = "Extra bytes in the last field of the bytecode")] |
| 93 | +fn test_should_fail_extra_bytes_in_last_field() { |
| 94 | + let mut packed_public_bytecode = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS]; |
| 95 | + packed_public_bytecode[0] = 30; |
| 96 | + // Last one should be zero |
| 97 | + let bytes = [ |
| 98 | + 0x0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
| 99 | + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, |
| 100 | + 0x1e, 0x01, |
| 101 | + ]; |
| 102 | + packed_public_bytecode[1] = Field::from_be_bytes(bytes); |
| 103 | + |
| 104 | + validate_bytes_encoding(packed_public_bytecode); |
| 105 | +} |
0 commit comments