From 8d844ea39d6b658f7e78d9a4a015ba52baf3f589 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Mon, 30 Oct 2023 07:48:40 +0300 Subject: [PATCH 1/6] MIR: add byte literals --- contrib/mir/Cargo.lock | 11 +++++++++-- contrib/mir/Cargo.toml | 1 + contrib/mir/src/ast.rs | 2 ++ contrib/mir/src/lexer.rs | 35 ++++++++++++++++++++++++++++++++-- contrib/mir/src/parser.rs | 10 +++++++++- contrib/mir/src/syntax.lalrpop | 4 +++- 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/contrib/mir/Cargo.lock b/contrib/mir/Cargo.lock index b1dda6b41f4a..2edd31fc2912 100644 --- a/contrib/mir/Cargo.lock +++ b/contrib/mir/Cargo.lock @@ -193,6 +193,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "indexmap" version = "2.0.0" @@ -257,9 +263,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "linux-raw-sys" @@ -326,6 +332,7 @@ name = "mir" version = "0.1.0" dependencies = [ "checked", + "hex", "lalrpop", "lalrpop-util", "logos", diff --git a/contrib/mir/Cargo.toml b/contrib/mir/Cargo.toml index 8e779c7d0404..3c9a07f1bb48 100644 --- a/contrib/mir/Cargo.toml +++ b/contrib/mir/Cargo.toml @@ -11,6 +11,7 @@ lalrpop-util = "0.20.0" checked = "0.5" thiserror = "1.0" logos = "0.13" +hex = "0.4" [[bin]] name = "tzt_runner" diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index d09f41df512f..b302eb2d1785 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -83,6 +83,7 @@ pub enum Value { Seq(Vec), Elt(Box<(Value, Value)>), Or(Box>), + Bytes(Vec), } impl Value { @@ -127,6 +128,7 @@ valuefrom! { <> bool, Value::Boolean; <> String, Value::String; <> (), |_| Value::Unit; + <> Vec, Value::Bytes; (L, R), |(l, r): (L, R)| Value::new_pair(l.into(), r.into()); Elt, |Elt(l, r): Elt| Value::new_elt(l.into(), r.into()); Option, |x: Option| Value::new_option(x.map(Into::into)); diff --git a/contrib/mir/src/lexer.rs b/contrib/mir/src/lexer.rs index 2ff4ca1d8797..4506241e0059 100644 --- a/contrib/mir/src/lexer.rs +++ b/contrib/mir/src/lexer.rs @@ -131,6 +131,9 @@ pub enum Tok { #[regex(r#""(\\.|[^\\"])*""#, lex_string)] String(String), + #[regex(r#"0x[0-9a-fA-F]*"#, lex_bytes)] + Bytes(Vec), + // regex as per https://tezos.gitlab.io/active/michelson.html#syntax #[regex(r"@%|@%%|%@|[@:%][_0-9a-zA-Z][_0-9a-zA-Z\.%@]*")] Annotation, @@ -149,12 +152,13 @@ pub enum Tok { impl std::fmt::Display for Tok { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self { + match self { Tok::Prim(PrimWithTzt::Prim(p)) => p.fmt(f), Tok::Prim(PrimWithTzt::TztPrim(p)) => p.fmt(f), Tok::Prim(PrimWithTzt::Underscore) => write!(f, "_"), Tok::Number(n) => n.fmt(f), Tok::String(s) => s.fmt(f), + Tok::Bytes(bs) => write!(f, "0x{}", hex::encode(bs)), Tok::Annotation => write!(f, ""), Tok::LParen => write!(f, "("), Tok::RParen => write!(f, ")"), @@ -165,7 +169,7 @@ impl std::fmt::Display for Tok { } } -#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum LexerError { #[error("unknown token")] UnknownToken, @@ -177,6 +181,8 @@ pub enum LexerError { UndefinedEscape(char), #[error(transparent)] PrimError(#[from] PrimError), + #[error("invalid hex sequence: {0}")] + InvalidHex(#[from] hex::FromHexError), } impl Default for LexerError { @@ -245,6 +251,12 @@ fn lex_string(lex: &mut Lexer) -> Result { Ok(res) } +/// Takes a lexed slice of hexadecimal digits prefixed by `0x`, removes the +/// prefix and converts the digits pairwise to `u8`. +fn lex_bytes(lex: &mut Lexer) -> Result, LexerError> { + Ok(hex::decode(&lex.slice()[2..])?) +} + #[cfg(test)] mod tests { use super::*; @@ -289,4 +301,23 @@ mod tests { "unknown primitive: foo" ) } + + #[test] + fn lex_bytes_test() { + #[track_caller] + fn assert_parse(s: &str, e: Result<[u8; N], &str>) { + assert_eq!( + Tok::lexer(s).map(|i| i.map_err(|x| x.to_string())).last(), + Some(e.map(|v| Tok::Bytes(v.to_vec())).map_err(|e| e.to_owned())) + ) + } + assert_parse("0x01", Ok([0x01])); + assert_parse("0x010203", Ok([0x01, 0x02, 0x03])); + assert_parse("0xfffe", Ok([0xff, 0xfe])); + assert_parse("0x0000", Ok([0x00, 0x00])); + assert_parse("0xabcd", Ok([0xab, 0xcd])); + assert_parse("0x", Ok([])); + assert_parse::<0>("0x1", Err("invalid hex sequence: Odd number of digits")); + assert_parse::<0>("0xzz", Err("unknown primitive: zz")); + } } diff --git a/contrib/mir/src/parser.rs b/contrib/mir/src/parser.rs index 53eb78c5d11e..8c165b5d64b9 100644 --- a/contrib/mir/src/parser.rs +++ b/contrib/mir/src/parser.rs @@ -11,7 +11,7 @@ use crate::syntax; use lalrpop_util::ParseError; use logos::Logos; -#[derive(Debug, PartialEq, Eq, thiserror::Error)] +#[derive(Debug, PartialEq, thiserror::Error)] pub enum ParserError { #[error("expected a natural from 0 to 1023 inclusive, but got {0}")] ExpectedU10(i128), @@ -320,4 +320,12 @@ mod tests { Instruction::Push((Type::new_contract(Type::Unit), Value::Unit)) ); } + + #[test] + fn bytes_push() { + assert_eq!( + parse("PUSH unit 0xdeadf00d").unwrap(), + Instruction::Push((Type::Unit, Value::Bytes(vec![0xde, 0xad, 0xf0, 0x0d]))) + ); + } } diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 1e607510854a..11209197ac88 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -34,6 +34,7 @@ extern { "amount" => Tok::Prim(TztPrim(TzP::amount)), number => Tok::Number(), string => Tok::String(), + bytes => Tok::Bytes(>), ann => Tok::Annotation, "parameter" => Tok::Prim(PT::Prim(Prim::parameter)), "storage" => Tok::Prim(PT::Prim(Prim::storage)), @@ -139,7 +140,8 @@ boolean: bool = { atomic_value: Value = { => Value::Number(n), => Value::Boolean(b), - => Value::String(<>), + string => Value::String(<>), + bytes => Value::Bytes(<>), "Unit" => Value::Unit, "None" => Value::Option(None), } -- GitLab From 180120d53d98bc2b882267429c5708eeac3b7cc3 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Mon, 30 Oct 2023 07:53:10 +0300 Subject: [PATCH 2/6] MIR: add address type --- contrib/mir/src/ast.rs | 3 ++- contrib/mir/src/lexer.rs | 1 + contrib/mir/src/parser.rs | 11 +++++++++++ contrib/mir/src/syntax.lalrpop | 2 ++ contrib/mir/src/typechecker.rs | 2 +- contrib/mir/src/typechecker/type_props.rs | 2 +- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index b302eb2d1785..9bf020f075bb 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -33,6 +33,7 @@ pub enum Type { Map(Box<(Type, Type)>), Or(Box<(Type, Type)>), Contract(Box), + Address, } impl Type { @@ -41,7 +42,7 @@ impl Type { pub fn size_for_gas(&self) -> usize { use Type::*; match self { - Nat | Int | Bool | Mutez | String | Unit | Operation => 1, + Nat | Int | Bool | Mutez | String | Unit | Operation | Address => 1, Pair(p) | Or(p) | Map(p) => 1 + p.0.size_for_gas() + p.1.size_for_gas(), Option(x) | List(x) | Contract(x) => 1 + x.size_for_gas(), } diff --git a/contrib/mir/src/lexer.rs b/contrib/mir/src/lexer.rs index 4506241e0059..26f7a0ee7f1b 100644 --- a/contrib/mir/src/lexer.rs +++ b/contrib/mir/src/lexer.rs @@ -95,6 +95,7 @@ defprim! { Right, IF_LEFT, contract, + address, } defprim! { diff --git a/contrib/mir/src/parser.rs b/contrib/mir/src/parser.rs index 8c165b5d64b9..dd9221f4990f 100644 --- a/contrib/mir/src/parser.rs +++ b/contrib/mir/src/parser.rs @@ -328,4 +328,15 @@ mod tests { Instruction::Push((Type::Unit, Value::Bytes(vec![0xde, 0xad, 0xf0, 0x0d]))) ); } + + #[test] + fn address_ty_push() { + assert_eq!( + parse("PUSH address \"tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw\"").unwrap(), + Instruction::Push(( + Type::Address, + Value::String("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw".to_owned()) + )) + ); + } } diff --git a/contrib/mir/src/syntax.lalrpop b/contrib/mir/src/syntax.lalrpop index 11209197ac88..9c7a066f7fad 100644 --- a/contrib/mir/src/syntax.lalrpop +++ b/contrib/mir/src/syntax.lalrpop @@ -52,6 +52,7 @@ extern { "map" => Tok::Prim(PT::Prim(Prim::map)), "or" => Tok::Prim(PT::Prim(Prim::or)), "contract" => Tok::Prim(PT::Prim(Prim::contract)), + "address" => Tok::Prim(PT::Prim(Prim::address)), "True" => Tok::Prim(PT::Prim(Prim::True)), "False" => Tok::Prim(PT::Prim(Prim::False)), "Unit" => Tok::Prim(PT::Prim(Prim::Unit)), @@ -109,6 +110,7 @@ atomic_type: Type = { "string" => Type::String, "unit" => Type::Unit, "operation" => Type::Operation, + "address" => Type::Address, } pair_args: Type = { diff --git a/contrib/mir/src/typechecker.rs b/contrib/mir/src/typechecker.rs index abaee6dada4a..e4d6d29f8c5d 100644 --- a/contrib/mir/src/typechecker.rs +++ b/contrib/mir/src/typechecker.rs @@ -141,7 +141,7 @@ fn verify_ty(ctx: &mut Ctx, t: &Type) -> Result<(), TcError> { use Type::*; ctx.gas.consume(gas::tc_cost::VERIFY_TYPE_STEP)?; match t { - Nat | Int | Bool | Mutez | String | Operation | Unit => Ok(()), + Nat | Int | Bool | Mutez | String | Operation | Unit | Address => Ok(()), Pair(tys) | Or(tys) => { verify_ty(ctx, &tys.0)?; verify_ty(ctx, &tys.1) diff --git a/contrib/mir/src/typechecker/type_props.rs b/contrib/mir/src/typechecker/type_props.rs index 9a3578559bac..ff1a0297c954 100644 --- a/contrib/mir/src/typechecker/type_props.rs +++ b/contrib/mir/src/typechecker/type_props.rs @@ -41,7 +41,7 @@ impl Type { gas.consume(tc_cost::TYPE_PROP_STEP)?; let invalid_type_prop = || Err(TcError::InvalidTypeProperty(prop, self.clone())); match self { - Nat | Int | Bool | Mutez | String | Unit => (), + Nat | Int | Bool | Mutez | String | Unit | Address => (), Operation => match prop { TypeProperty::Comparable | TypeProperty::Passable -- GitLab From d8e6c1dc63370aa9796ac6c5bb6169509864c29a Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Mon, 30 Oct 2023 10:26:00 +0300 Subject: [PATCH 3/6] MIR: add tezos_crypto_rs to dependencies --- contrib/mir/Cargo.lock | 772 ++++++++++++++++++++++++++++++++++++++++- contrib/mir/Cargo.toml | 1 + 2 files changed, 769 insertions(+), 4 deletions(-) diff --git a/contrib/mir/Cargo.lock b/contrib/mir/Cargo.lock index 2edd31fc2912..020747567373 100644 --- a/contrib/mir/Cargo.lock +++ b/contrib/mir/Cargo.lock @@ -11,6 +11,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "ascii-canvas" version = "3.0.0" @@ -26,6 +38,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "beef" version = "0.5.2" @@ -59,6 +83,43 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a30d0edd9dd1c60ddb42b80341c7852f6f985279a5c1a83659dcb65899dec99" +dependencies = [ + "cc", + "glob", + "threadpool", + "which", + "zeroize", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.0.83" @@ -83,18 +144,117 @@ dependencies = [ "num-traits", ] +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "cryptoxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382ce8820a5bb815055d3553a610e8cb542b2d767bbacea99038afda96cd760d" + +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.33", +] + +[[package]] +name = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -116,12 +276,59 @@ dependencies = [ "winapi", ] +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der", + "elliptic-curve", + "hmac", + "signature 1.3.2", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.1.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2 0.10.8", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "elliptic-curve" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" +dependencies = [ + "crypto-bigint", + "ff", + "generic-array", + "group", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "ena" version = "0.14.2" @@ -158,6 +365,28 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -170,6 +399,27 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -178,7 +428,24 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -187,6 +454,15 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.3.2" @@ -199,6 +475,25 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "indexmap" version = "2.0.0" @@ -261,12 +556,70 @@ dependencies = [ "regex", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "linux-raw-sys" version = "0.4.7" @@ -309,7 +662,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn", + "syn 2.0.33", ] [[package]] @@ -336,6 +689,7 @@ dependencies = [ "lalrpop", "lalrpop-util", "logos", + "tezos_crypto_rs", "thiserror", ] @@ -345,6 +699,29 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand 0.7.3", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -352,6 +729,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", ] [[package]] @@ -360,6 +748,23 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "p256" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2 0.9.9", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -408,6 +813,18 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "platforms" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -423,6 +840,32 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.0", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.7.5", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.33" @@ -432,6 +875,86 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -456,7 +979,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] @@ -496,6 +1019,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.13" @@ -515,12 +1047,90 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.33", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" + [[package]] name = "siphasher" version = "0.3.11" @@ -546,6 +1156,41 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.33" @@ -557,6 +1202,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", +] + [[package]] name = "term" version = "0.7.0" @@ -568,6 +1226,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "tezos_crypto_rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576b69129eabf1edca392ff5e763610d448275fd2724d05464bb3542829c6d64" +dependencies = [ + "anyhow", + "base58", + "blst", + "byteorder", + "cryptoxide", + "ed25519-dalek", + "hex", + "libsecp256k1", + "num-bigint", + "num-traits", + "p256", + "proptest", + "rand 0.7.3", + "serde", + "strum", + "strum_macros", + "thiserror", + "zeroize", +] + [[package]] name = "thiserror" version = "1.0.48" @@ -585,7 +1269,16 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.33", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", ] [[package]] @@ -597,24 +1290,75 @@ dependencies = [ "crunchy", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "winapi" version = "0.3.9" @@ -702,3 +1446,23 @@ name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.33", +] diff --git a/contrib/mir/Cargo.toml b/contrib/mir/Cargo.toml index 3c9a07f1bb48..f27d8eceaf38 100644 --- a/contrib/mir/Cargo.toml +++ b/contrib/mir/Cargo.toml @@ -12,6 +12,7 @@ checked = "0.5" thiserror = "1.0" logos = "0.13" hex = "0.4" +tezos_crypto_rs = "0.5" [[bin]] name = "tzt_runner" -- GitLab From dc47a75e998c82ee7b89693ababc9c381323ce45 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Tue, 31 Oct 2023 08:23:58 +0300 Subject: [PATCH 4/6] MIR: add address values --- contrib/mir/src/ast.rs | 4 + contrib/mir/src/ast/michelson_address.rs | 249 +++++++++++++++++ .../src/ast/michelson_address/address_hash.rs | 187 +++++++++++++ .../src/ast/michelson_address/entrypoint.rs | 238 ++++++++++++++++ .../mir/src/ast/michelson_address/error.rs | 29 ++ contrib/mir/src/gas.rs | 10 + contrib/mir/src/typechecker.rs | 257 +++++++++++++++++- 7 files changed, 962 insertions(+), 12 deletions(-) create mode 100644 contrib/mir/src/ast/michelson_address.rs create mode 100644 contrib/mir/src/ast/michelson_address/address_hash.rs create mode 100644 contrib/mir/src/ast/michelson_address/entrypoint.rs create mode 100644 contrib/mir/src/ast/michelson_address/error.rs diff --git a/contrib/mir/src/ast.rs b/contrib/mir/src/ast.rs index 9bf020f075bb..cacda66d9433 100644 --- a/contrib/mir/src/ast.rs +++ b/contrib/mir/src/ast.rs @@ -6,6 +6,7 @@ /******************************************************************************/ pub mod comparable; +pub mod michelson_address; pub mod michelson_list; pub mod or; pub mod parsed; @@ -13,6 +14,7 @@ pub mod typechecked; use std::collections::BTreeMap; +pub use michelson_address::*; pub use michelson_list::MichelsonList; pub use or::Or; pub use parsed::{ParsedInstruction, ParsedStage}; @@ -156,6 +158,7 @@ pub enum TypedValue { List(MichelsonList), Map(BTreeMap), Or(Box>), + Address(Address), } pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value { @@ -189,6 +192,7 @@ pub fn typed_value_to_value_optimized(tv: TypedValue) -> Value { TV::Option(None) => V::Option(None), TV::Option(Some(r)) => V::new_option(Some(typed_value_to_value_optimized(*r))), TV::Or(x) => V::new_or(x.map(typed_value_to_value_optimized)), + TV::Address(x) => V::Bytes(x.to_bytes_vec()), } } diff --git a/contrib/mir/src/ast/michelson_address.rs b/contrib/mir/src/ast/michelson_address.rs new file mode 100644 index 000000000000..c5c16981cd5f --- /dev/null +++ b/contrib/mir/src/ast/michelson_address.rs @@ -0,0 +1,249 @@ +/******************************************************************************/ +/* */ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) [2023] Serokell */ +/* */ +/******************************************************************************/ + +pub mod address_hash; +pub mod entrypoint; +pub mod error; + +pub use self::address_hash::AddressHash; +pub use self::entrypoint::Entrypoint; +pub use self::error::AddressError; + +use address_hash::check_size; + +#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)] +pub struct Address { + pub hash: AddressHash, + pub entrypoint: Entrypoint, +} + +impl Address { + pub fn from_base58_check(data: &str) -> Result { + let (hash, ep) = if let Some(ep_sep_pos) = data.find('%') { + (&data[..ep_sep_pos], &data[ep_sep_pos + 1..]) + } else { + (data, "") + }; + Ok(Address { + hash: AddressHash::from_base58_check(hash)?, + entrypoint: Entrypoint::try_from(ep)?, + }) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + check_size(bytes, AddressHash::BYTE_SIZE, "bytes")?; + + let (hash, ep) = bytes.split_at(AddressHash::BYTE_SIZE); + Ok(Address { + hash: AddressHash::from_bytes(hash)?, + entrypoint: Entrypoint::try_from(ep)?, + }) + } + + pub fn is_default_ep(&self) -> bool { + self.entrypoint.is_default() + } + + pub fn to_bytes(&self, out: &mut Vec) { + self.hash.to_bytes(out); + if !self.is_default_ep() { + out.extend_from_slice(self.entrypoint.as_bytes()) + } + } + + pub fn to_bytes_vec(&self) -> Vec { + let mut out = Vec::new(); + self.to_bytes(&mut out); + out + } + + pub fn to_base58_check(&self) -> String { + if self.is_default_ep() { + self.hash.to_base58_check() + } else { + format!( + "{}%{}", + self.hash.to_base58_check(), + self.entrypoint.as_str() + ) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_base58_to_bin() { + // address with explicit, but empty, entrypoint + assert_eq!( + Address::from_base58_check("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw%") + .unwrap() + .to_bytes_vec(), + hex::decode("00002422090f872dfd3a39471bb23f180e6dfed030f3").unwrap(), + ); + + // address with explicit default entrypoint + assert_eq!( + Address::from_base58_check("tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw%default") + .unwrap() + .to_bytes_vec(), + hex::decode("00002422090f872dfd3a39471bb23f180e6dfed030f3").unwrap(), + ); + + for (b58, hex) in FIXTURES { + assert_eq!( + Address::from_base58_check(b58).unwrap().to_bytes_vec(), + hex::decode(hex).unwrap(), + ); + } + } + + #[test] + fn test_bin_to_base58() { + // explicit default entrypoint is apparently forbidden in binary encoding + assert!(matches!( + Address::from_bytes( + &hex::decode("00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c74").unwrap() + ), + Err(AddressError::WrongFormat(_)), + )); + + // unknown implicit tag + assert_eq!( + dbg!(Address::from_bytes( + &hex::decode("00ff7b09f782e0bcd67739510afa819d85976119d5ef").unwrap() + )), + Err(AddressError::UnknownPrefix("0x00ff".to_owned())), + ); + + // unknown tag + assert_eq!( + Address::from_bytes( + &hex::decode("ffff7b09f782e0bcd67739510afa819d85976119d5ef").unwrap() + ), + Err(AddressError::UnknownPrefix("0xff".to_owned())), + ); + + for (b58, hex) in FIXTURES { + assert_eq!( + Address::from_bytes(&hex::decode(hex).unwrap()) + .unwrap() + .to_base58_check(), + b58, + ); + } + } + + // binary representation produced by running + // + // `octez-client --mode mockup run script 'parameter address; storage unit; + // code { CAR; FAILWITH }' on storage Unit and input "\"$addr\""` + const FIXTURES: [(&str, &str); 25] = [ + ( + "tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw", + "00002422090f872dfd3a39471bb23f180e6dfed030f3", + ), + ( + "tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ", + "000049d0be8c2987e04e080f4d73cbe24d8bf83997e2", + ), + ( + "tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy", + "0000682343b6fe7589573e11db2b87fd206b936e2a79", + ), + ( + "tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF", + "000075deb97789e2429f2b9bb5dba1b1e4a061e832a3", + ), + ( + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar", + "00007b09f782e0bcd67739510afa819d85976119d5ef626172", + ), + ( + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls", + "00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c73", + ), + ( + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j", + "00007b09f782e0bcd67739510afa819d85976119d5ef", + ), + ( + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu", + "00007b09f782e0bcd67739510afa819d85976119d5ef64656661756c75", + ), + ( + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo", + "00007b09f782e0bcd67739510afa819d85976119d5ef666f6f", + ), + ( + "tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv", + "0000ed6586813c9085c8b6252ec3a654ee0e36a0f0e2", + ), + ( + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar", + "00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe626172", + ), + ( + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH", + "00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe", + ), + ( + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo", + "00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe666f6f", + ), + ( + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar", + "00025cfa532f50de3e12befc0ad21603835dd7698d35626172", + ), + ( + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "00025cfa532f50de3e12befc0ad21603835dd7698d35", + ), + ( + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo", + "00025cfa532f50de3e12befc0ad21603835dd7698d35666f6f", + ), + ( + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar", + "00036342f30484dd46b6074373aa6ddca9dfb70083d6626172", + ), + ( + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN", + "00036342f30484dd46b6074373aa6ddca9dfb70083d6", + ), + ( + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo", + "00036342f30484dd46b6074373aa6ddca9dfb70083d6666f6f", + ), + ( + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar", + "011f2d825fdd9da219235510335e558520235f4f5400626172", + ), + ( + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye", + "011f2d825fdd9da219235510335e558520235f4f5400", + ), + ( + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo", + "011f2d825fdd9da219235510335e558520235f4f5400666f6f", + ), + ( + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar", + "03d601f22256d2ad1faec0c64374e527c6e62f2e5a00626172", + ), + ( + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf", + "03d601f22256d2ad1faec0c64374e527c6e62f2e5a00", + ), + ( + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo", + "03d601f22256d2ad1faec0c64374e527c6e62f2e5a00666f6f", + ), + ]; +} diff --git a/contrib/mir/src/ast/michelson_address/address_hash.rs b/contrib/mir/src/ast/michelson_address/address_hash.rs new file mode 100644 index 000000000000..f9d43a896bc9 --- /dev/null +++ b/contrib/mir/src/ast/michelson_address/address_hash.rs @@ -0,0 +1,187 @@ +/******************************************************************************/ +/* */ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) [2023] Serokell */ +/* */ +/******************************************************************************/ + +use super::AddressError; + +use tezos_crypto_rs::hash::{ + ContractKt1Hash, ContractTz1Hash, ContractTz2Hash, ContractTz3Hash, ContractTz4Hash, Hash, + HashTrait, SmartRollupHash, +}; + +macro_rules! address_hash_type_and_impls { + ($($con:ident($ty:ident)),* $(,)*) => { + #[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)] + pub enum AddressHash { + $($con($ty)),* + } + + $(impl From<$ty> for AddressHash { + fn from(value: $ty) -> Self { + AddressHash::$con(value) + } + })* + + impl AsRef<[u8]> for AddressHash { + fn as_ref(&self) -> &[u8] { + match self { + $(AddressHash::$con($ty(h)))|* => h, + } + } + } + + impl From for Vec { + fn from(value: AddressHash) -> Self { + match value { + $(AddressHash::$con($ty(h)))|* => h, + } + } + } + + impl AddressHash { + pub fn to_base58_check(&self) -> String { + match self { + $(AddressHash::$con(h) => h.to_base58_check()),* + } + } + } + }; +} + +address_hash_type_and_impls! { + Tz1(ContractTz1Hash), + Tz2(ContractTz2Hash), + Tz3(ContractTz3Hash), + Tz4(ContractTz4Hash), + Kt1(ContractKt1Hash), + Sr1(SmartRollupHash), +} + +impl TryFrom<&[u8]> for AddressHash { + type Error = AddressError; + fn try_from(value: &[u8]) -> Result { + Self::from_bytes(value) + } +} + +impl TryFrom<&str> for AddressHash { + type Error = AddressError; + fn try_from(value: &str) -> Result { + Self::from_base58_check(value) + } +} + +pub(super) fn check_size(data: &[u8], min_size: usize, name: &str) -> Result<(), AddressError> { + let size = data.len(); + if size < min_size { + Err(AddressError::WrongFormat(format!( + "address must be at least {min_size} {name} long, but it is {size} {name} long" + ))) + } else { + Ok(()) + } +} + +const TAG_IMPLICIT: u8 = 0; +const TAG_KT1: u8 = 1; +const TAG_SR1: u8 = 3; +const TAG_TZ1: u8 = 0; +const TAG_TZ2: u8 = 1; +const TAG_TZ3: u8 = 2; +const TAG_TZ4: u8 = 3; +const PADDING_IMPLICIT: &[u8] = &[]; +const PADDING_SMART: &[u8] = &[0]; + +impl AddressHash { + // all address hashes are 20 bytes in length + pub const HASH_SIZE: usize = 20; + // +2 for tags: implicit addresses use 2-byte, and KT1/sr1 add zero-byte + // padding to the end + pub const BYTE_SIZE: usize = Self::HASH_SIZE + 2; + pub const BASE58_SIZE: usize = 36; + + pub fn from_base58_check(data: &str) -> Result { + use AddressHash::*; + + check_size(data.as_bytes(), Self::BASE58_SIZE, "characters")?; + + Ok(match &data[0..3] { + "KT1" => Kt1(HashTrait::from_b58check(data)?), + "sr1" => Sr1(HashTrait::from_b58check(data)?), + "tz1" => Tz1(HashTrait::from_b58check(data)?), + "tz2" => Tz2(HashTrait::from_b58check(data)?), + "tz3" => Tz3(HashTrait::from_b58check(data)?), + "tz4" => Tz4(HashTrait::from_b58check(data)?), + s => return Err(AddressError::UnknownPrefix(s.to_owned())), + }) + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + use AddressHash::*; + + check_size(bytes, Self::BYTE_SIZE, "bytes")?; + let validate_padding_byte = || match bytes.last().unwrap() { + 0 => Ok(()), + b => Err(AddressError::WrongFormat(format!( + "address must be padded with byte 0x00, but it was padded with 0x{}", + hex::encode([*b]) + ))), + }; + Ok(match bytes[0] { + // implicit addresses + TAG_IMPLICIT => match bytes[1] { + TAG_TZ1 => Tz1(HashTrait::try_from_bytes(&bytes[2..])?), + TAG_TZ2 => Tz2(HashTrait::try_from_bytes(&bytes[2..])?), + TAG_TZ3 => Tz3(HashTrait::try_from_bytes(&bytes[2..])?), + TAG_TZ4 => Tz4(HashTrait::try_from_bytes(&bytes[2..])?), + _ => { + return Err(AddressError::UnknownPrefix(format!( + "0x{}", + hex::encode(&bytes[..2]) + ))) + } + }, + TAG_KT1 => { + validate_padding_byte()?; + Kt1(HashTrait::try_from_bytes(&bytes[1..bytes.len() - 1])?) + } + // 2 is txr1 addresses, which are deprecated + TAG_SR1 => { + validate_padding_byte()?; + Sr1(HashTrait::try_from_bytes(&bytes[1..bytes.len() - 1])?) + } + _ => { + return Err(AddressError::UnknownPrefix(format!( + "0x{}", + hex::encode(&bytes[..1]) + ))) + } + }) + } + + pub fn to_bytes(&self, out: &mut Vec) { + use AddressHash::*; + fn go(out: &mut Vec, tag: &[u8], hash: impl AsRef, sep: &[u8]) { + out.extend_from_slice(tag); + out.extend_from_slice(hash.as_ref()); + out.extend_from_slice(sep); + } + match self { + Tz1(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ1], hash, PADDING_IMPLICIT), + Tz2(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ2], hash, PADDING_IMPLICIT), + Tz3(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ3], hash, PADDING_IMPLICIT), + Tz4(hash) => go(out, &[TAG_IMPLICIT, TAG_TZ4], hash, PADDING_IMPLICIT), + Kt1(hash) => go(out, &[TAG_KT1], hash, PADDING_SMART), + Sr1(hash) => go(out, &[TAG_SR1], hash, PADDING_SMART), + } + } + + pub fn to_bytes_vec(&self) -> Vec { + let mut out = Vec::new(); + self.to_bytes(&mut out); + out + } +} diff --git a/contrib/mir/src/ast/michelson_address/entrypoint.rs b/contrib/mir/src/ast/michelson_address/entrypoint.rs new file mode 100644 index 000000000000..521735414e70 --- /dev/null +++ b/contrib/mir/src/ast/michelson_address/entrypoint.rs @@ -0,0 +1,238 @@ +/******************************************************************************/ +/* */ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) [2023] Serokell */ +/* */ +/******************************************************************************/ + +use super::AddressError; + +#[derive(Debug, Clone, Eq, PartialOrd, Ord, PartialEq)] +pub struct Entrypoint(String); + +// NB: default entrypoint is represented as literal "default", because it +// affects comparision for addresses. +const DEFAULT_EP_NAME: &str = "default"; +const MAX_EP_LEN: usize = 31; + +impl Default for Entrypoint { + fn default() -> Self { + Entrypoint(DEFAULT_EP_NAME.to_owned()) + } +} + +impl Entrypoint { + pub fn is_default(&self) -> bool { + self.0 == DEFAULT_EP_NAME + } + + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +impl TryFrom<&str> for Entrypoint { + type Error = AddressError; + fn try_from(s: &str) -> Result { + Entrypoint::try_from(s.to_owned()) + } +} + +impl TryFrom for Entrypoint { + type Error = AddressError; + fn try_from(s: String) -> Result { + if s.is_empty() { + Ok(Entrypoint::default()) + } else { + check_ep_name(s.as_bytes())?; + Ok(Entrypoint(s)) + } + } +} + +impl TryFrom<&[u8]> for Entrypoint { + type Error = AddressError; + fn try_from(s: &[u8]) -> Result { + if s.is_empty() { + Ok(Entrypoint::default()) + } else { + check_ep_name(s)?; + // SAFETY: we just checked all bytes are valid ASCII + let ep = Entrypoint(unsafe { std::str::from_utf8_unchecked(s).to_owned() }); + if ep.is_default() { + return Err(AddressError::WrongFormat( + "explicit default entrypoint is forbidden in binary encoding".to_owned(), + )); + } + Ok(ep) + } + } +} + +fn check_ep_name(ep: &[u8]) -> Result<(), AddressError> { + if ep.len() > MAX_EP_LEN { + return Err(AddressError::WrongFormat(format!( + "entrypoint name must be at most {} characters long, but it is {} characters long", + MAX_EP_LEN, + ep.len() + ))); + } + let mut first_char = true; + for c in ep { + // direct encoding of the regex defined in + // https://tezos.gitlab.io/alpha/michelson.html#syntax + match c { + b'_' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => Ok(()), + b'.' | b'%' | b'@' if !first_char => Ok(()), + c => Err(AddressError::WrongFormat(format!( + "forbidden byte in entrypoint name: {}", + hex::encode([*c]) + ))), + }?; + first_char = false; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default() { + assert_eq!( + Entrypoint::default(), + Entrypoint(DEFAULT_EP_NAME.to_owned()) + ) + } + + #[test] + fn test_from_str() { + assert_eq!(Entrypoint::try_from(""), Ok(Entrypoint::default())); + assert_eq!(Entrypoint::try_from("default"), Ok(Entrypoint::default())); + assert_eq!( + Entrypoint::try_from("foo"), + Ok(Entrypoint("foo".to_owned())) + ); + assert_eq!( + Entrypoint::try_from("foo.bar"), + Ok(Entrypoint("foo.bar".to_owned())) + ); + assert_eq!( + Entrypoint::try_from("q".repeat(31).as_str()), + Ok(Entrypoint("q".repeat(31))) + ); + // too long + assert!(matches!( + Entrypoint::try_from("q".repeat(32).as_str()), + Err(AddressError::WrongFormat(_)) + )); + // unicode + assert!(matches!( + Entrypoint::try_from("संसर"), + Err(AddressError::WrongFormat(_)) + )); + // forbidden character + assert!(matches!( + Entrypoint::try_from("!"), + Err(AddressError::WrongFormat(_)) + )); + } + + #[test] + fn test_from_string() { + // most of this is tested in test_from_str, as one delegates to the + // other, so only the basic tests here + assert_eq!( + Entrypoint::try_from("".to_owned()), + Ok(Entrypoint::default()) + ); + assert_eq!( + Entrypoint::try_from("default".to_owned()), + Ok(Entrypoint::default()) + ); + assert_eq!( + Entrypoint::try_from("foo".to_owned()), + Ok(Entrypoint("foo".to_owned())) + ); + } + + #[test] + fn test_from_bytes() { + // explicit default entrypoints are forbidden in binary + assert!(matches!( + Entrypoint::try_from(b"default" as &[u8]), + Err(AddressError::WrongFormat(_)) + )); + assert_eq!( + Entrypoint::try_from(b"" as &[u8]), + Ok(Entrypoint::default()) + ); + assert_eq!( + Entrypoint::try_from(b"foo" as &[u8]), + Ok(Entrypoint("foo".to_owned())) + ); + + assert_eq!( + Entrypoint::try_from(b"foo.bar" as &[u8]), + Ok(Entrypoint("foo.bar".to_owned())) + ); + assert_eq!( + Entrypoint::try_from("q".repeat(31).as_bytes()), + Ok(Entrypoint("q".repeat(31))) + ); + // too long + assert!(matches!( + Entrypoint::try_from("q".repeat(32).as_bytes()), + Err(AddressError::WrongFormat(_)) + )); + // unicode + assert!(matches!( + Entrypoint::try_from("संसर".as_bytes()), + Err(AddressError::WrongFormat(_)) + )); + // forbidden character + assert!(matches!( + Entrypoint::try_from(b"!" as &[u8]), + Err(AddressError::WrongFormat(_)) + )); + } + + #[test] + fn test_check_ep_name() { + assert_eq!(check_ep_name(&[b'q'; 31]), Ok(())); + + // more than 31 bytes + assert!(matches!( + check_ep_name(&[b'q'; 32]), + Err(AddressError::WrongFormat(_)) + )); + + // '.', '%', '@' are allowed + for i in ['.', '%', '@'] { + assert_eq!(check_ep_name(format!("foo{i}bar").as_bytes()), Ok(())); + + // but not as the first character + assert!(matches!( + check_ep_name(format!("{i}bar").as_bytes()), + Err(AddressError::WrongFormat(_)) + )); + } + + // ! is forbidden + assert!(matches!( + check_ep_name(b"foo!"), + Err(AddressError::WrongFormat(_)) + )); + + // unicode is forbidden + assert!(matches!( + check_ep_name("नमस्ते".as_bytes()), + Err(AddressError::WrongFormat(_)) + )); + } +} diff --git a/contrib/mir/src/ast/michelson_address/error.rs b/contrib/mir/src/ast/michelson_address/error.rs new file mode 100644 index 000000000000..abb384a19e01 --- /dev/null +++ b/contrib/mir/src/ast/michelson_address/error.rs @@ -0,0 +1,29 @@ +/******************************************************************************/ +/* */ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) [2023] Serokell */ +/* */ +/******************************************************************************/ + +use tezos_crypto_rs::base58::FromBase58CheckError; +use tezos_crypto_rs::hash::FromBytesError; + +#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] +pub enum AddressError { + #[error("unknown address prefix: {0}")] + UnknownPrefix(String), + #[error("wrong address format: {0}")] + WrongFormat(String), +} + +impl From for AddressError { + fn from(value: FromBase58CheckError) -> Self { + Self::WrongFormat(value.to_string()) + } +} + +impl From for AddressError { + fn from(value: FromBytesError) -> Self { + Self::WrongFormat(value.to_string()) + } +} diff --git a/contrib/mir/src/gas.rs b/contrib/mir/src/gas.rs index 000ed326232d..acf78e606c7f 100644 --- a/contrib/mir/src/gas.rs +++ b/contrib/mir/src/gas.rs @@ -97,6 +97,16 @@ pub mod tc_cost { // Taken to be the same as VERIFY_TYPE_STEP, but that's a guess pub const TYPE_PROP_STEP: u32 = 60; + // corresponds to cost_B58CHECK_ENCODING_PUBLIC_KEY_HASH_bls in the + // protocol. the protocol computes cost as + // `max(bls,ed25519,p256,secp256k1)`, which happens to be `bls` + pub const KEY_HASH_READABLE: u32 = 3200; + + // corresponds to cost_ENCODING_PUBLIC_KEY_HASH_bls in the + // protocol. the protocol computes cost as + // `max(bls,ed25519,p256,secp256k1)`, which happens to be `bls` + pub const KEY_HASH_OPTIMIZED: u32 = 80; + fn variadic(depth: u16) -> Result { let depth = Checked::from(depth as u32); (depth * 50).as_gas_cost() diff --git a/contrib/mir/src/typechecker.rs b/contrib/mir/src/typechecker.rs index e4d6d29f8c5d..afa6858ef98a 100644 --- a/contrib/mir/src/typechecker.rs +++ b/contrib/mir/src/typechecker.rs @@ -51,6 +51,8 @@ pub enum TcError { stack: TypeStack, reason: Option, }, + #[error(transparent)] + AddressError(#[from] AddressError), } #[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] @@ -567,25 +569,25 @@ fn typecheck_instruction( /// Typecheck a value. Assumes passed the type is valid, i.e. doesn't contain /// illegal types like `set operation` or `contract operation`. fn typecheck_value(ctx: &mut Ctx, t: &Type, v: Value) -> Result { - use Type::*; + use Type as T; use TypedValue as TV; use Value as V; ctx.gas.consume(gas::tc_cost::VALUE_STEP)?; Ok(match (t, v) { - (Nat, V::Number(n)) => TV::Nat(n.try_into()?), - (Int, V::Number(n)) => TV::Int(n), - (Bool, V::Boolean(b)) => TV::Bool(b), - (Mutez, V::Number(n)) if n >= 0 => TV::Mutez(n.try_into()?), - (String, V::String(s)) => TV::String(s), - (Unit, V::Unit) => TV::Unit, - (Pair(pt), V::Pair(pv)) => { + (T::Nat, V::Number(n)) => TV::Nat(n.try_into()?), + (T::Int, V::Number(n)) => TV::Int(n), + (T::Bool, V::Boolean(b)) => TV::Bool(b), + (T::Mutez, V::Number(n)) if n >= 0 => TV::Mutez(n.try_into()?), + (T::String, V::String(s)) => TV::String(s), + (T::Unit, V::Unit) => TV::Unit, + (T::Pair(pt), V::Pair(pv)) => { let (tl, tr) = pt.as_ref(); let (vl, vr) = *pv; let l = typecheck_value(ctx, tl, vl)?; let r = typecheck_value(ctx, tr, vr)?; TV::new_pair(l, r) } - (Or(ot), V::Or(val)) => { + (T::Or(ot), V::Or(val)) => { let (tl, tr) = ot.as_ref(); let typed_val = match *val { crate::ast::Or::Left(lv) => crate::ast::Or::Left(typecheck_value(ctx, tl, lv)?), @@ -593,19 +595,19 @@ fn typecheck_value(ctx: &mut Ctx, t: &Type, v: Value) -> Result match v { + (T::Option(ty), V::Option(v)) => match v { Some(v) => { let v = typecheck_value(ctx, ty, *v)?; TV::new_option(Some(v)) } None => TV::new_option(None), }, - (List(ty), V::Seq(vs)) => TV::List( + (T::List(ty), V::Seq(vs)) => TV::List( vs.into_iter() .map(|v| typecheck_value(ctx, ty, v)) .collect::>()?, ), - (Map(m), V::Seq(vs)) => { + (T::Map(m), V::Seq(vs)) => { let (tk, tv) = m.as_ref(); let tc_elt = |v: Value| -> Result<(TypedValue, TypedValue), TcError> { match v { @@ -645,6 +647,14 @@ fn typecheck_value(ctx: &mut Ctx, t: &Type, v: Value) -> Result = elts.into_iter().collect(); TV::Map(map) } + (T::Address, V::String(str)) => { + ctx.gas.consume(gas::tc_cost::KEY_HASH_READABLE)?; + TV::Address(Address::from_base58_check(&str)?) + } + (T::Address, V::Bytes(bs)) => { + ctx.gas.consume(gas::tc_cost::KEY_HASH_OPTIMIZED)?; + TV::Address(Address::from_bytes(&bs)?) + } (t, v) => return Err(TcError::InvalidValueForType(v, t.clone())), }) } @@ -2250,4 +2260,227 @@ mod typecheck_tests { )) ); } + + #[test] + fn test_push_address() { + #[track_caller] + fn test_ok(lit: &str, bytes: &str, exp: Address) { + let exp = Ok(Push(TypedValue::Address(exp))); + assert_eq!( + &typecheck_instruction( + parse(&format!("PUSH address {lit}")).unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + &exp + ); + assert_eq!( + &typecheck_instruction( + parse(&format!("PUSH address {bytes}")).unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + &exp + ); + } + fn hex>(con: fn(Vec) -> T, hex: &str, ep: &str) -> Address { + Address { + hash: con(hex::decode(hex).unwrap()).into(), + entrypoint: Entrypoint::try_from(ep).unwrap(), + } + } + use tezos_crypto_rs::hash::*; + // hex representations are obtained via `octez-client hash data` + test_ok( + r#""tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j""#, + "0x00007b09f782e0bcd67739510afa819d85976119d5ef", + hex( + ContractTz1Hash, + "7b09f782e0bcd67739510afa819d85976119d5ef", + "default", + ), + ); + test_ok( + r#""tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH""#, + "0x00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe", + hex( + ContractTz2Hash, + "0a053e3d8b622a993d3182e3f6cc5638ff5f12fe", + "default", + ), + ); + test_ok( + r#""tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r""#, + "0x00025cfa532f50de3e12befc0ad21603835dd7698d35", + hex( + ContractTz3Hash, + "5cfa532f50de3e12befc0ad21603835dd7698d35", + "default", + ), + ); + test_ok( + r#""tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN""#, + "0x00036342f30484dd46b6074373aa6ddca9dfb70083d6", + hex( + ContractTz4Hash, + "6342f30484dd46b6074373aa6ddca9dfb70083d6", + "default", + ), + ); + test_ok( + r#""KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye""#, + "0x011f2d825fdd9da219235510335e558520235f4f5400", + hex( + ContractKt1Hash, + "1f2d825fdd9da219235510335e558520235f4f54", + "default", + ), + ); + test_ok( + r#""sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf""#, + "0x03d601f22256d2ad1faec0c64374e527c6e62f2e5a00", + hex( + SmartRollupHash, + "d601f22256d2ad1faec0c64374e527c6e62f2e5a", + "default", + ), + ); + // with entrypoints + test_ok( + r#""tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo""#, + "0x00007b09f782e0bcd67739510afa819d85976119d5ef666f6f", + hex( + ContractTz1Hash, + "7b09f782e0bcd67739510afa819d85976119d5ef", + "foo", + ), + ); + test_ok( + r#""tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo""#, + "0x00010a053e3d8b622a993d3182e3f6cc5638ff5f12fe666f6f", + hex( + ContractTz2Hash, + "0a053e3d8b622a993d3182e3f6cc5638ff5f12fe", + "foo", + ), + ); + test_ok( + r#""tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo""#, + "0x00025cfa532f50de3e12befc0ad21603835dd7698d35666f6f", + hex( + ContractTz3Hash, + "5cfa532f50de3e12befc0ad21603835dd7698d35", + "foo", + ), + ); + test_ok( + r#""tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo""#, + "0x00036342f30484dd46b6074373aa6ddca9dfb70083d6666f6f", + hex( + ContractTz4Hash, + "6342f30484dd46b6074373aa6ddca9dfb70083d6", + "foo", + ), + ); + test_ok( + r#""KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo""#, + "0x011f2d825fdd9da219235510335e558520235f4f5400666f6f", + hex( + ContractKt1Hash, + "1f2d825fdd9da219235510335e558520235f4f54", + "foo", + ), + ); + test_ok( + r#""sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo""#, + "0x03d601f22256d2ad1faec0c64374e527c6e62f2e5a00666f6f", + hex( + SmartRollupHash, + "d601f22256d2ad1faec0c64374e527c6e62f2e5a", + "foo", + ), + ); + + macro_rules! assert_matches { + ($e:expr, $p:pat $(if $cond:expr)?) => { + match $e { + $p $(if $cond)? => (), + _ => panic!("expected {:?} to match {}", $e, stringify!($p)), + } + }; + } + + assert_matches!( + typecheck_instruction( + parse("PUSH address \"tz1foobarfoobarfoobarfoobarfoobarfoo\"").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address \"tz9foobarfoobarfoobarfoobarfoobarfoo\"").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::UnknownPrefix(s))) if s == "tz9" + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address \"tz\"").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0x0001fffe").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0xff00fe0000000000000000000000000000000000000000").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::UnknownPrefix(p))) if p == "0xff" + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0x00fffe0000000000000000000000000000000000000000").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::UnknownPrefix(p))) if p == "0x00ff" + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0x00").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0x011f2d825fdd9da219235510335e558520235f4f5401666f6f").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + assert_matches!( + typecheck_instruction( + parse("PUSH address 0x03d601f22256d2ad1faec0c64374e527c6e62f2e5a666f6f").unwrap(), + &mut Ctx::default(), + &mut tc_stk![], + ), + Err(TcError::AddressError(AddressError::WrongFormat(_))) + ); + } } -- GitLab From 71749085660906b8e38d8f4e37ce618cd049233c Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Tue, 31 Oct 2023 08:24:47 +0300 Subject: [PATCH 5/6] MIR: add comparison for addresses --- contrib/mir/src/ast/comparable.rs | 86 +++++++++++++++++++++++++++++++ contrib/mir/src/gas.rs | 2 + 2 files changed, 88 insertions(+) diff --git a/contrib/mir/src/ast/comparable.rs b/contrib/mir/src/ast/comparable.rs index cd437f674c0c..51c974f10c3e 100644 --- a/contrib/mir/src/ast/comparable.rs +++ b/contrib/mir/src/ast/comparable.rs @@ -13,6 +13,7 @@ impl PartialOrd for TypedValue { (Pair(l), Pair(r)) => l.partial_cmp(r), (Option(x), Option(y)) => x.as_deref().partial_cmp(&y.as_deref()), (Or(x), Or(y)) => x.as_ref().partial_cmp(y.as_ref()), + (Address(l), Address(r)) => l.partial_cmp(r), _ => None, } } @@ -91,6 +92,46 @@ mod tests { assert_eq!(Bool(true).partial_cmp(&Int(5)), None); } + #[test] + fn compare_addrs() { + // ordering was verified against octez-client, see script below + let ordered_addrs = [ + "tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw", + "tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ", + "tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy", + "tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF", + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar", + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls", + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j", + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu", + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo", + "tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv", + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar", + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH", + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo", + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar", + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r", + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo", + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar", + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN", + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo", + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar", + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye", + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo", + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar", + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf", + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo", + ] + .map(|x| TypedValue::Address(crate::ast::Address::from_base58_check(x).unwrap())); + + for (i, addr_i) in ordered_addrs.iter().enumerate() { + for (j, addr_j) in ordered_addrs.iter().enumerate() { + assert_eq!(addr_i.partial_cmp(addr_j), i.partial_cmp(&j)); + assert_eq!(addr_i.cmp(addr_j), i.cmp(&j)); + } + } + } + #[test] #[should_panic(expected = "Comparing incomparable values in TypedValue")] fn compare_different_comparable() { @@ -99,3 +140,48 @@ mod tests { let _ = Bool(true).cmp(&Int(5)); //panics } } + +/* +Script to verify address ordering. Should print "with -1" for all checked address pairs. + +``` +#!/bin/bash + +addrs=( + "tz1Nw5nr152qddEjKT2dKBH8XcBMDAg72iLw" + "tz1SNL5w4RFRbCWRMB4yDWvoRQrPQxZmNzeQ" + "tz1V8fDHpHzN8RrZqiYCHaJM9EocsYZch5Cy" + "tz1WPGZjP9eHGqD9DkiRJ1xGRU1wEMY19AAF" + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%bar" + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defauls" + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j" + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%defaulu" + "tz1WrbkDrzKVqcGXkjw4Qk4fXkjXpAJuNP1j%foo" + "tz1hHGTh6Yk4k7d2PiTcBUeMvw6fJCFikedv" + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%bar" + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH" + "tz29EDhZ4D3XueHxm5RGZsJLHRtj3qSA2MzH%foo" + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%bar" + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r" + "tz3UoffC7FG7zfpmvmjUmUeAaHvzdcUvAj6r%foo" + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%bar" + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN" + "tz4J46gb6DxDFYxkex8k9sKiYZwjuiaoNSqN%foo" + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%bar" + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye" + "KT1BRd2ka5q2cPRdXALtXD1QZ38CPam2j1ye%foo" + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%bar" + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf" + "sr1RYurGZtN8KNSpkMcCt9CgWeUaNkzsAfXf%foo" +) + +prev="" +for addr in "${addrs[@]}"; do + if [ -n "$prev" ]; then + echo $prev $addr + octez-client --mode mockup run script 'parameter address; storage address; code { UNPAIR; SWAP; COMPARE; FAILWITH }' on storage "\"$prev\"" and input "\"$addr\"" 2>&1 | grep '^with' + fi + prev="$addr" +done +``` +*/ diff --git a/contrib/mir/src/gas.rs b/contrib/mir/src/gas.rs index acf78e606c7f..fce194ba98c2 100644 --- a/contrib/mir/src/gas.rs +++ b/contrib/mir/src/gas.rs @@ -236,6 +236,7 @@ pub mod interpret_cost { (c + compare(&l.0, &r.0)? + compare(&l.1, &r.1)?).as_gas_cost() }; let cmp_option = Checked::from(10u32); + const ADDRESS_SIZE: usize = 20 + 31; // hash size + max entrypoint size Ok(match (v1, v2) { (V::Nat(l), V::Nat(r)) => { // NB: eventually when using BigInts, use BigInt::bits() &c @@ -257,6 +258,7 @@ pub mod interpret_cost { (Some(l), Some(r)) => cmp_option + compare(l, r)?, } .as_gas_cost()?, + (V::Address(..), V::Address(..)) => cmp_bytes(ADDRESS_SIZE, ADDRESS_SIZE)?, _ => unreachable!("Comparison of incomparable values"), }) } -- GitLab From 26db2e16904aa2a587db2b85b00cf3618494b401 Mon Sep 17 00:00:00 2001 From: Nikolay Yakimov Date: Tue, 31 Oct 2023 10:31:05 +0300 Subject: [PATCH 6/6] MIR: TryFrom instacnes for Address --- contrib/mir/src/ast/michelson_address.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/contrib/mir/src/ast/michelson_address.rs b/contrib/mir/src/ast/michelson_address.rs index c5c16981cd5f..3f51da216f44 100644 --- a/contrib/mir/src/ast/michelson_address.rs +++ b/contrib/mir/src/ast/michelson_address.rs @@ -74,6 +74,20 @@ impl Address { } } +impl TryFrom<&[u8]> for Address { + type Error = AddressError; + fn try_from(value: &[u8]) -> Result { + Self::from_bytes(value) + } +} + +impl TryFrom<&str> for Address { + type Error = AddressError; + fn try_from(value: &str) -> Result { + Self::from_base58_check(value) + } +} + #[cfg(test)] mod tests { use super::*; -- GitLab