From 21823483a55dc3f7be227772da5c4b1061398990 Mon Sep 17 00:00:00 2001 From: Vincent Bernardoff Date: Tue, 5 Jun 2018 19:27:58 +0200 Subject: [PATCH] Crypto: add P256 cryptography --- .gitlab-ci.yml | 91 +++--- src/bin_client/test/test_basic.sh | 4 + .../client_keys_commands.ml | 2 +- src/lib_crypto/base58.ml | 6 +- src/lib_crypto/base58.mli | 4 + src/lib_crypto/jbuild | 1 + src/lib_crypto/p256.ml | 266 ++++++++++++++++++ src/lib_crypto/p256.mli | 13 + src/lib_crypto/secp256k1.ml | 3 +- src/lib_crypto/signature.ml | 121 ++++++-- src/lib_crypto/signature.mli | 4 + src/lib_crypto/tezos-crypto.opam | 1 + src/lib_protocol_environment/sigs/jbuild | 1 + src/lib_protocol_environment/sigs/v1/p256.mli | 12 + .../sigs/v1/signature.mli | 2 + .../tezos_protocol_environment.ml | 4 + .../tezos_protocol_environment.mli | 3 + .../lib_protocol/src/contract_repr.ml | 4 + .../lib_protocol/src/contract_repr.mli | 1 + src/proto_alpha/lib_protocol/src/storage.ml | 11 + 20 files changed, 476 insertions(+), 78 deletions(-) create mode 100644 src/lib_crypto/p256.ml create mode 100644 src/lib_crypto/p256.mli create mode 100644 src/lib_protocol_environment/sigs/v1/p256.mli diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e7721dd6..43a687e3b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -300,217 +300,222 @@ opam:11:tezos-rpc: variables: package: tezos-rpc -opam:12:tezos-crypto: +opam:12:uecc: + <<: *opam_definition + variables: + package: uecc + +opam:13:tezos-crypto: <<: *opam_definition variables: package: tezos-crypto -opam:13:tezos-micheline: +opam:14:tezos-micheline: <<: *opam_definition variables: package: tezos-micheline -opam:14:lmdb: +opam:15:lmdb: <<: *opam_definition variables: package: lmdb -opam:15:pbkdf: +opam:16:pbkdf: <<: *opam_definition variables: package: pbkdf -opam:16:ocplib-resto-cohttp: +opam:17:ocplib-resto-cohttp: <<: *opam_definition variables: package: ocplib-resto-cohttp -opam:17:tezos-base: +opam:18:tezos-base: <<: *opam_definition variables: package: tezos-base -opam:18:irmin-lmdb: +opam:19:irmin-lmdb: <<: *opam_definition variables: package: irmin-lmdb -opam:19:bip39: +opam:20:bip39: <<: *opam_definition variables: package: bip39 -opam:20:tezos-rpc-http: +opam:21:tezos-rpc-http: <<: *opam_definition variables: package: tezos-rpc-http -opam:21:tezos-shell-services: +opam:22:tezos-shell-services: <<: *opam_definition variables: package: tezos-shell-services -opam:22:tezos-stdlib-unix: +opam:23:tezos-stdlib-unix: <<: *opam_definition variables: package: tezos-stdlib-unix -opam:23:tezos-storage: +opam:24:tezos-storage: <<: *opam_definition variables: package: tezos-storage -opam:24:tezos-protocol-environment-sigs: +opam:25:tezos-protocol-environment-sigs: <<: *opam_definition variables: package: tezos-protocol-environment-sigs -opam:25:tezos-client-base: +opam:26:tezos-client-base: <<: *opam_definition variables: package: tezos-client-base -opam:26:tezos-protocol-compiler: +opam:27:tezos-protocol-compiler: <<: *opam_definition variables: package: tezos-protocol-compiler -opam:27:tezos-signer-services: +opam:28:tezos-signer-services: <<: *opam_definition variables: package: tezos-signer-services -opam:28:tezos-protocol-alpha: +opam:29:tezos-protocol-alpha: <<: *opam_definition variables: package: tezos-protocol-alpha -opam:29:tezos-protocol-environment: +opam:30:tezos-protocol-environment: <<: *opam_definition variables: package: tezos-protocol-environment -opam:30:tezos-signer-backends: +opam:31:tezos-signer-backends: <<: *opam_definition variables: package: tezos-signer-backends -opam:31:tezos-client-alpha: +opam:32:tezos-client-alpha: <<: *opam_definition variables: package: tezos-client-alpha -opam:32:tezos-client-commands: +opam:33:tezos-client-commands: <<: *opam_definition variables: package: tezos-client-commands -opam:33:tezos-protocol-environment-shell: +opam:34:tezos-protocol-environment-shell: <<: *opam_definition variables: package: tezos-protocol-environment-shell -opam:34:tezos-baking-alpha: +opam:35:tezos-baking-alpha: <<: *opam_definition variables: package: tezos-baking-alpha -opam:35:tezos-protocol-genesis: +opam:36:tezos-protocol-genesis: <<: *opam_definition variables: package: tezos-protocol-genesis -opam:36:ocplib-resto-json: +opam:37:ocplib-resto-json: <<: *opam_definition variables: package: ocplib-resto-json -opam:37:tezos-protocol-updater: +opam:38:tezos-protocol-updater: <<: *opam_definition variables: package: tezos-protocol-updater -opam:38:tezos-p2p: +opam:39:tezos-p2p: <<: *opam_definition variables: package: tezos-p2p -opam:39:tezos-baking-alpha-commands: +opam:40:tezos-baking-alpha-commands: <<: *opam_definition variables: package: tezos-baking-alpha-commands -opam:40:tezos-client-alpha-commands: +opam:41:tezos-client-alpha-commands: <<: *opam_definition variables: package: tezos-client-alpha-commands -opam:41:tezos-client-base-unix: +opam:42:tezos-client-base-unix: <<: *opam_definition variables: package: tezos-client-base-unix -opam:42:tezos-client-genesis: +opam:43:tezos-client-genesis: <<: *opam_definition variables: package: tezos-client-genesis -opam:43:ocplib-ezresto: +opam:44:ocplib-ezresto: <<: *opam_definition variables: package: ocplib-ezresto -opam:44:tezos-embedded-protocol-alpha: +opam:45:tezos-embedded-protocol-alpha: <<: *opam_definition variables: package: tezos-embedded-protocol-alpha -opam:45:tezos-embedded-protocol-demo: +opam:46:tezos-embedded-protocol-demo: <<: *opam_definition variables: package: tezos-embedded-protocol-demo -opam:46:tezos-embedded-protocol-genesis: +opam:47:tezos-embedded-protocol-genesis: <<: *opam_definition variables: package: tezos-embedded-protocol-genesis -opam:47:tezos-shell: +opam:48:tezos-shell: <<: *opam_definition variables: package: tezos-shell -opam:48:tezos-client: +opam:49:tezos-client: <<: *opam_definition variables: package: tezos-client -opam:49:ocplib-ezresto-directory: +opam:50:ocplib-ezresto-directory: <<: *opam_definition variables: package: ocplib-ezresto-directory -opam:50:tezos-baker-alpha: +opam:51:tezos-baker-alpha: <<: *opam_definition variables: package: tezos-baker-alpha -opam:51:tezos-protocol-demo: +opam:52:tezos-protocol-demo: <<: *opam_definition variables: package: tezos-protocol-demo -opam:52:tezos-signer: +opam:53:tezos-signer: <<: *opam_definition variables: package: tezos-signer -opam:53:tezos-node: +opam:54:tezos-node: <<: *opam_definition variables: package: tezos-node -opam:54:ocplib-json-typed-browser: +opam:55:ocplib-json-typed-browser: <<: *opam_definition variables: package: ocplib-json-typed-browser diff --git a/src/bin_client/test/test_basic.sh b/src/bin_client/test/test_basic.sh index 4bc35d287..af63064a8 100755 --- a/src/bin_client/test/test_basic.sh +++ b/src/bin_client/test/test_basic.sh @@ -28,10 +28,12 @@ key2=bar key3=boo key4=king key5=queen +key6=p256 $client gen keys $key1 $client gen keys $key2 --sig secp256k1 $client gen keys $key3 --sig ed25519 +$client gen keys $key6 --sig p256 $client list known identities $client get balance for bootstrap1 @@ -39,10 +41,12 @@ $client get balance for bootstrap1 bake_after $client transfer 1,000 from bootstrap1 to $key1 bake_after $client transfer 2,000 from bootstrap1 to $key2 bake_after $client transfer 3,000 from bootstrap1 to $key3 +bake_after $client transfer 4,000 from bootstrap1 to $key6 $client get balance for $key1 | assert "1,000 ꜩ" $client get balance for $key2 | assert "2,000 ꜩ" $client get balance for $key3 | assert "3,000 ꜩ" +$client get balance for $key6 | assert "4,000 ꜩ" bake_after $client transfer 1,000 from $key2 to $key1 -fee 0 $client get balance for $key1 | assert "2,000 ꜩ" diff --git a/src/lib_client_commands/client_keys_commands.ml b/src/lib_client_commands/client_keys_commands.ml index 08ed95715..fcf1d56fe 100644 --- a/src/lib_client_commands/client_keys_commands.ml +++ b/src/lib_client_commands/client_keys_commands.ml @@ -29,7 +29,7 @@ let sig_algo_arg = ~doc:"use custom signature algorithm" ~long:"sig" ~short:'s' - ~placeholder:"ed25519|secp256k1" + ~placeholder:"ed25519|secp256k1|p256" ~default: "ed25519" (Signature.algo_param ()) diff --git a/src/lib_crypto/base58.ml b/src/lib_crypto/base58.ml index 2436fa942..e78f5cd4d 100644 --- a/src/lib_crypto/base58.ml +++ b/src/lib_crypto/base58.ml @@ -308,9 +308,8 @@ module Prefix = struct (* 20 *) let ed25519_public_key_hash = "\006\161\159" (* tz1(36) *) - - (* 20 *) let secp256k1_public_key_hash = "\006\161\161" (* tz2(36) *) + let p256_public_key_hash = "\006\161\164" (* tz3(36) *) (* 16 *) let cryptobox_public_key_hash = "\153\103" (* id(30) *) @@ -319,14 +318,17 @@ module Prefix = struct let ed25519_seed = "\013\015\058\007" (* edsk(54) *) let ed25519_public_key = "\013\015\037\217" (* edpk(54) *) let secp256k1_secret_key = "\017\162\224\201" (* spsk(54) *) + let p256_secret_key = "\016\081\238\189" (* p2sk(54) *) (* 33 *) let secp256k1_public_key = "\003\254\226\086" (* sppk(55) *) + let p256_public_key = "\003\178\139\127" (* p2pk(55) *) (* 64 *) let ed25519_secret_key = "\043\246\078\007" (* edsk(98) *) let ed25519_signature = "\009\245\205\134\018" (* edsig(99) *) let secp256k1_signature = "\013\115\101\019\063" (* spsig1(99) *) + let p256_signature = "\054\240\044\052" (* p2sig(98) *) let generic_signature = "\004\130\043" (* sig(96) *) (* 4 *) diff --git a/src/lib_crypto/base58.mli b/src/lib_crypto/base58.mli index 94ccfedcd..ba33f15e4 100644 --- a/src/lib_crypto/base58.mli +++ b/src/lib_crypto/base58.mli @@ -19,6 +19,7 @@ module Prefix : sig val context_hash: string val ed25519_public_key_hash: string val secp256k1_public_key_hash: string + val p256_public_key_hash: string val cryptobox_public_key_hash: string val ed25519_seed: string val ed25519_public_key: string @@ -27,6 +28,9 @@ module Prefix : sig val secp256k1_public_key: string val secp256k1_secret_key: string val secp256k1_signature: string + val p256_public_key: string + val p256_secret_key: string + val p256_signature: string val generic_signature: string val chain_id: string diff --git a/src/lib_crypto/jbuild b/src/lib_crypto/jbuild index 23f4143e7..902a189e0 100644 --- a/src/lib_crypto/jbuild +++ b/src/lib_crypto/jbuild @@ -18,6 +18,7 @@ blake2 hacl secp256k1 + uecc zarith)))) (alias diff --git a/src/lib_crypto/p256.ml b/src/lib_crypto/p256.ml new file mode 100644 index 000000000..832fd68c5 --- /dev/null +++ b/src/lib_crypto/p256.ml @@ -0,0 +1,266 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +module Public_key_hash = Blake2B.Make(Base58)(struct + let name = "P256.Public_key_hash" + let title = "A P256 public key hash" + let b58check_prefix = Base58.Prefix.p256_public_key_hash + let size = Some 20 + end) + +let () = + Base58.check_encoded_prefix Public_key_hash.b58check_encoding "tz3" 36 + +open Uecc + +module Public_key = struct + + type t = (secp256r1, public) key + + let name = "P256.Public_key" + let title = "A P256 public key" + + let to_bytes = to_bytes ~compress:true + let of_bytes_opt = pk_of_bytes secp256r1 + + let to_string s = MBytes.to_string (to_bytes s) + let of_string_opt s = of_bytes_opt (MBytes.of_string s) + + let size = compressed_size secp256r1 + + type Base58.data += + | Data of t + + let b58check_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.p256_public_key + ~length: size + ~to_raw: to_string + ~of_raw: of_string_opt + ~wrap: (fun x -> Data x) + + let () = + Base58.check_encoded_prefix b58check_encoding "p2pk" 55 + + let hash v = + Public_key_hash.hash_bytes [to_bytes v] + + include Compare.Make(struct + type nonrec t = t + let compare a b = + MBytes.compare (to_bytes a) (to_bytes b) + end) + + include Helpers.MakeRaw(struct + type nonrec t = t + let name = name + let of_bytes_opt = of_bytes_opt + let of_string_opt = of_string_opt + let to_string = to_string + end) + + include Helpers.MakeB58(struct + type nonrec t = t + let title = title + let name = name + let b58check_encoding = b58check_encoding + end) + + include Helpers.MakeEncoder(struct + type nonrec t = t + let name = name + let title = title + let raw_encoding = + let open Data_encoding in + conv to_bytes of_bytes_exn (Fixed.bytes size) + let of_b58check = of_b58check + let of_b58check_opt = of_b58check_opt + let of_b58check_exn = of_b58check_exn + let to_b58check = to_b58check + let to_short_b58check = to_short_b58check + end) + + let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) + +end + +module Secret_key = struct + + type t = (secp256r1, secret) key + + let name = "P256.Secret_key" + let title = "A P256 secret key" + + let size = sk_size secp256r1 + + let of_bytes_opt buf = + Option.map ~f:fst (sk_of_bytes secp256r1 buf) + + let to_bytes = to_bytes ~compress:true + + let to_string s = MBytes.to_string (to_bytes s) + let of_string_opt s = of_bytes_opt (MBytes.of_string s) + + let to_public_key = neuterize + + type Base58.data += + | Data of t + + let b58check_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.p256_secret_key + ~length: size + ~to_raw: to_string + ~of_raw: of_string_opt + ~wrap: (fun x -> Data x) + + let () = + Base58.check_encoded_prefix b58check_encoding "p2sk" 54 + + include Compare.Make(struct + type nonrec t = t + let compare a b = + MBytes.compare (to_bytes a) (to_bytes b) + end) + + include Helpers.MakeRaw(struct + type nonrec t = t + let name = name + let of_bytes_opt = of_bytes_opt + let of_string_opt = of_string_opt + let to_string = to_string + end) + + include Helpers.MakeB58(struct + type nonrec t = t + let title = title + let name = name + let b58check_encoding = b58check_encoding + end) + + include Helpers.MakeEncoder(struct + type nonrec t = t + let name = name + let title = title + let raw_encoding = + let open Data_encoding in + conv to_bytes of_bytes_exn (Fixed.bytes size) + let of_b58check = of_b58check + let of_b58check_opt = of_b58check_opt + let of_b58check_exn = of_b58check_exn + let to_b58check = to_b58check + let to_short_b58check = to_short_b58check + end) + + let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) + +end + +type t = MBytes.t + +type watermark = MBytes.t + +let name = "P256" +let title = "A P256 signature" + +let size = pk_size secp256r1 + +let of_bytes_opt s = + if MBytes.length s = size then Some s else None + +let to_bytes s = s + +let to_string s = MBytes.to_string (to_bytes s) +let of_string_opt s = of_bytes_opt (MBytes.of_string s) + +type Base58.data += + | Data of t + +let b58check_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.p256_signature + ~length: size + ~to_raw: to_string + ~of_raw: of_string_opt + ~wrap: (fun x -> Data x) + +let () = + Base58.check_encoded_prefix b58check_encoding "p2sig" 98 + +include Helpers.MakeRaw(struct + type nonrec t = t + let name = name + let of_bytes_opt = of_bytes_opt + let of_string_opt = of_string_opt + let to_string = to_string + end) + +include Helpers.MakeB58(struct + type nonrec t = t + let title = title + let name = name + let b58check_encoding = b58check_encoding + end) + +include Helpers.MakeEncoder(struct + type nonrec t = t + let name = name + let title = title + let raw_encoding = + let open Data_encoding in + conv to_bytes of_bytes_exn (Fixed.bytes size) + let of_b58check = of_b58check + let of_b58check_opt = of_b58check_opt + let of_b58check_exn = of_b58check_exn + let to_b58check = to_b58check + let to_short_b58check = to_short_b58check + end) + +let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) + +let zero = of_bytes_exn (MBytes.make size '\000') + +let sign ?watermark sk msg = + let msg = + Blake2B.to_bytes @@ + Blake2B.hash_bytes @@ + match watermark with + | None -> [msg] + | Some prefix -> [ prefix ; msg ] in + match sign sk msg with + | None -> + (* Will never happen in practice. This can only happen in case + of RNG error. *) + invalid_arg "P256.sign: internal error" + | Some signature -> signature + +let check ?watermark public_key signature msg = + let msg = + Blake2B.to_bytes @@ + Blake2B.hash_bytes @@ + match watermark with + | None -> [msg] + | Some prefix -> [ prefix ; msg ] in + verify public_key ~msg ~signature + +let generate_key ?(seed=Rand.generate 32) () = + let seedlen = MBytes.length seed in + if seedlen < 32 then + invalid_arg (Printf.sprintf "P256.generate_key: seed must be at \ + least 32 bytes long (was %d)" seedlen) ; + match sk_of_bytes secp256r1 seed with + | None -> invalid_arg "P256.generate_key: invalid seed (very rare!)" + | Some (sk, pk) -> + let pkh = Public_key.hash pk in + pkh, pk, sk + +include Compare.Make(struct + type nonrec t = t + let compare = MBytes.compare + end) diff --git a/src/lib_crypto/p256.mli b/src/lib_crypto/p256.mli new file mode 100644 index 000000000..5198c4657 --- /dev/null +++ b/src/lib_crypto/p256.mli @@ -0,0 +1,13 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +(** Tezos - P256 cryptography *) + +include S.SIGNATURE with type watermark = MBytes.t +include S.RAW_DATA with type t := t diff --git a/src/lib_crypto/secp256k1.ml b/src/lib_crypto/secp256k1.ml index a1a8ff7f7..d1de8083a 100644 --- a/src/lib_crypto/secp256k1.ml +++ b/src/lib_crypto/secp256k1.ml @@ -62,7 +62,7 @@ module Public_key = struct include Compare.Make(struct type nonrec t = t let compare a b = - MBytes.compare (Key.buffer a) (Key.buffer b) + MBytes.compare (to_bytes a) (to_bytes b) end) include Helpers.MakeRaw(struct @@ -264,4 +264,3 @@ let generate_key ?(seed=Rand.generate 32) () = let pk = Key.neuterize_exn context sk in let pkh = Public_key.hash pk in pkh, pk, sk - diff --git a/src/lib_crypto/signature.ml b/src/lib_crypto/signature.ml index 95dc81cf1..f6cb66d1f 100644 --- a/src/lib_crypto/signature.ml +++ b/src/lib_crypto/signature.ml @@ -12,14 +12,17 @@ open Error_monad type public_key_hash = | Ed25519 of Ed25519.Public_key_hash.t | Secp256k1 of Secp256k1.Public_key_hash.t + | P256 of P256.Public_key_hash.t type public_key = | Ed25519 of Ed25519.Public_key.t | Secp256k1 of Secp256k1.Public_key.t + | P256 of P256.Public_key.t type secret_key = | Ed25519 of Ed25519.Secret_key.t | Secp256k1 of Secp256k1.Secret_key.t + | P256 of P256.Secret_key.t type watermark = | Block_header @@ -32,9 +35,10 @@ module Public_key_hash = struct type t = public_key_hash = | Ed25519 of Ed25519.Public_key_hash.t | Secp256k1 of Secp256k1.Public_key_hash.t + | P256 of P256.Public_key_hash.t let name = "Signature.Public_key_hash" - let title = "A Secp256k1 or Ed25519 public key hash" + let title = "A Ed25519, Secp256k1, or P256 public key hash" type Base58.data += Data of t (* unused *) let b58check_encoding = (* unused *) @@ -56,7 +60,11 @@ module Public_key_hash = struct case (Tag 1) Secp256k1.Public_key_hash.encoding ~title:"Secp256k1" (function Secp256k1 x -> Some x | _ -> None) - (function x -> Secp256k1 x) + (function x -> Secp256k1 x) ; + case (Tag 2) + ~title:"P256" P256.Public_key_hash.encoding + (function P256 x -> Some x | _ -> None) + (function x -> P256 x) ] let to_bytes s = @@ -82,6 +90,7 @@ module Public_key_hash = struct match Base58.decode s with | Some Ed25519.Public_key_hash.Data pkh -> Some (Ed25519 pkh) | Some Secp256k1.Public_key_hash.Data pkh -> Some (Secp256k1 pkh) + | Some P256.Public_key_hash.Data pkh -> Some (P256 pkh) | _ -> None let of_b58check_exn s = @@ -99,14 +108,17 @@ module Public_key_hash = struct let to_b58check = function | Ed25519 pkh -> Ed25519.Public_key_hash.to_b58check pkh | Secp256k1 pkh -> Secp256k1.Public_key_hash.to_b58check pkh + | P256 pkh -> P256.Public_key_hash.to_b58check pkh let to_short_b58check = function | Ed25519 pkh -> Ed25519.Public_key_hash.to_short_b58check pkh | Secp256k1 pkh -> Secp256k1.Public_key_hash.to_short_b58check pkh + | P256 pkh -> P256.Public_key_hash.to_short_b58check pkh let to_path key l = match key with | Ed25519 h -> "ed25519" :: Ed25519.Public_key_hash.to_path h l | Secp256k1 h -> "secp256k1" :: Secp256k1.Public_key_hash.to_path h l + | P256 h -> "p256" :: P256.Public_key_hash.to_path h l let of_path = function | "ed25519" :: q -> begin @@ -119,10 +131,17 @@ module Public_key_hash = struct | Some pkh -> Some (Secp256k1 pkh) | None -> None end + | "p256" :: q -> begin + match P256.Public_key_hash.of_path q with + | Some pkh -> Some (P256 pkh) + | None -> None + end | _ -> assert false (* FIXME classification des erreurs *) + let of_path_exn = function | "ed25519" :: q -> Ed25519 (Ed25519.Public_key_hash.of_path_exn q) | "secp256k1" :: q -> Secp256k1 (Secp256k1.Public_key_hash.of_path_exn q) + | "p256" :: q -> P256 (P256.Public_key_hash.of_path_exn q) | _ -> assert false (* FIXME classification des erreurs *) let path_length = @@ -139,12 +158,13 @@ module Public_key_hash = struct type nonrec t = t let compare a b = match (a, b) with - | Ed25519 _ , Secp256k1 _ -> 1 - | Secp256k1 _, Ed25519 _ -> -1 | Ed25519 x, Ed25519 y -> Ed25519.Public_key_hash.compare x y | Secp256k1 x, Secp256k1 y -> Secp256k1.Public_key_hash.compare x y + | P256 x, P256 y -> + P256.Public_key_hash.compare x y + | _ -> Pervasives.compare a b end) include Helpers.MakeEncoder(struct @@ -180,22 +200,24 @@ module Public_key = struct type t = public_key = | Ed25519 of Ed25519.Public_key.t | Secp256k1 of Secp256k1.Public_key.t + | P256 of P256.Public_key.t let name = "Signature.Public_key" - let title = "A Secp256k1 or Ed25519 public key" + let title = "A Ed25519, Secp256k1, or P256 public key" let hash pk = match pk with | Ed25519 pk -> Public_key_hash.Ed25519 (Ed25519.Public_key.hash pk) | Secp256k1 pk -> Public_key_hash.Secp256k1 (Secp256k1.Public_key.hash pk) + | P256 pk -> Public_key_hash.P256 (P256.Public_key.hash pk) include Compare.Make(struct type nonrec t = t let compare a b = match (a, b) with - | (Ed25519 _ , Secp256k1 _) -> 1 - | (Secp256k1 _, Ed25519 _ ) -> -1 - | (Ed25519 x, Ed25519 y) -> Ed25519.Public_key.compare x y - | (Secp256k1 x, Secp256k1 y) -> Secp256k1.Public_key.compare x y + | Ed25519 x, Ed25519 y -> Ed25519.Public_key.compare x y + | Secp256k1 x, Secp256k1 y -> Secp256k1.Public_key.compare x y + | P256 x, P256 y -> P256.Public_key.compare x y + | _ -> Pervasives.compare a b end) type Base58.data += Data of t (* unused *) @@ -211,6 +233,7 @@ module Public_key = struct match Base58.decode s with | Some (Ed25519.Public_key.Data public_key) -> Some (Ed25519 public_key) | Some (Secp256k1.Public_key.Data public_key) -> Some (Secp256k1 public_key) + | Some (P256.Public_key.Data public_key) -> Some (P256 public_key) | _ -> None let of_b58check_exn s = @@ -228,10 +251,12 @@ module Public_key = struct let to_b58check = function | Ed25519 pk -> Ed25519.Public_key.to_b58check pk | Secp256k1 pk -> Secp256k1.Public_key.to_b58check pk + | P256 pk -> P256.Public_key.to_b58check pk let to_short_b58check = function | Ed25519 pk -> Ed25519.Public_key.to_short_b58check pk | Secp256k1 pk -> Secp256k1.Public_key.to_short_b58check pk + | P256 pk -> P256.Public_key.to_short_b58check pk include Helpers.MakeEncoder(struct type nonrec t = t @@ -248,7 +273,11 @@ module Public_key = struct case (Tag 1) Secp256k1.Public_key.encoding ~title:"Secp256k1" (function Secp256k1 x -> Some x | _ -> None) - (function x -> Secp256k1 x) + (function x -> Secp256k1 x) ; + case + ~title:"P256" (Tag 2) P256.Public_key.encoding + (function P256 x -> Some x | _ -> None) + (function x -> P256 x) ] let of_b58check = of_b58check let of_b58check_opt = of_b58check_opt @@ -266,21 +295,23 @@ module Secret_key = struct type t = secret_key = | Ed25519 of Ed25519.Secret_key.t | Secp256k1 of Secp256k1.Secret_key.t + | P256 of P256.Secret_key.t let name = "Signature.Secret_key" - let title = "A Secp256k1 or Ed25519 secret key" + let title = "A Ed25519, Secp256k1 or P256 secret key" let to_public_key = function | Ed25519 sk -> Public_key.Ed25519 (Ed25519.Secret_key.to_public_key sk) | Secp256k1 sk -> Public_key.Secp256k1 (Secp256k1.Secret_key.to_public_key sk) + | P256 sk -> Public_key.P256 (P256.Secret_key.to_public_key sk) include Compare.Make(struct type nonrec t = t let compare a b = match (a, b) with - | (Ed25519 _ , Secp256k1 _) -> 1 - | (Secp256k1 _, Ed25519 _ ) -> -1 - | (Ed25519 x, Ed25519 y) -> Ed25519.Secret_key.compare x y - | (Secp256k1 x, Secp256k1 y) -> Secp256k1.Secret_key.compare x y + | Ed25519 x, Ed25519 y -> Ed25519.Secret_key.compare x y + | Secp256k1 x, Secp256k1 y -> Secp256k1.Secret_key.compare x y + | P256 x, P256 y -> P256.Secret_key.compare x y + | _ -> Pervasives.compare a b end) type Base58.data += Data of t (* unused *) @@ -296,6 +327,7 @@ module Secret_key = struct match Base58.decode b with | Some (Ed25519.Secret_key.Data sk) -> Some (Ed25519 sk) | Some (Secp256k1.Secret_key.Data sk) -> Some (Secp256k1 sk) + | Some (P256.Secret_key.Data sk) -> Some (P256 sk) | _ -> None let of_b58check_exn s = @@ -313,10 +345,12 @@ module Secret_key = struct let to_b58check = function | Ed25519 sk -> Ed25519.Secret_key.to_b58check sk | Secp256k1 sk -> Secp256k1.Secret_key.to_b58check sk + | P256 sk -> P256.Secret_key.to_b58check sk let to_short_b58check = function | Ed25519 sk -> Ed25519.Secret_key.to_short_b58check sk | Secp256k1 sk -> Secp256k1.Secret_key.to_short_b58check sk + | P256 sk -> P256.Secret_key.to_short_b58check sk include Helpers.MakeEncoder(struct type nonrec t = t @@ -333,7 +367,11 @@ module Secret_key = struct case (Tag 1) Secp256k1.Secret_key.encoding ~title:"Secp256k1" (function Secp256k1 x -> Some x | _ -> None) - (function x -> Secp256k1 x) + (function x -> Secp256k1 x) ; + case (Tag 2) + ~title:"P256" P256.Secret_key.encoding + (function P256 x -> Some x | _ -> None) + (function x -> P256 x) ] let of_b58check = of_b58check let of_b58check_opt = of_b58check_opt @@ -349,18 +387,21 @@ end type t = | Ed25519 of Ed25519.t | Secp256k1 of Secp256k1.t + | P256 of P256.t | Unknown of MBytes.t let name = "Signature" -let title = "A Secp256k1 or Ed25519 signature" +let title = "A Ed25519, Secp256k1 or P256 signature" -let () = assert (Ed25519.size = Secp256k1.size) -let size = Ed25519.size +let size = + assert (Ed25519.size = Secp256k1.size && Secp256k1.size = P256.size) ; + Ed25519.size let to_bytes = function - | Unknown b -> b | Ed25519 b -> Ed25519.to_bytes b | Secp256k1 b -> Secp256k1.to_bytes b + | P256 b -> P256.to_bytes b + | Unknown b -> b let of_bytes_opt s = if MBytes.length s = size then Some (Unknown s) else None @@ -405,6 +446,10 @@ let of_b58check_opt s = Option.map (Secp256k1.of_b58check_opt s) ~f: (fun x -> Secp256k1 x) + else if TzString.has_prefix ~prefix:P256.b58check_encoding.encoded_prefix s then + Option.map + (P256.of_b58check_opt s) + ~f: (fun x -> P256 x) else Base58.simple_decode b58check_encoding s @@ -423,11 +468,13 @@ let of_b58check s = let to_b58check = function | Ed25519 b -> Ed25519.to_b58check b | Secp256k1 b -> Secp256k1.to_b58check b + | P256 b -> P256.to_b58check b | Unknown b -> Base58.simple_encode b58check_encoding (Unknown b) let to_short_b58check = function | Ed25519 b -> Ed25519.to_short_b58check b | Secp256k1 b -> Secp256k1.to_short_b58check b + | P256 b -> P256.to_short_b58check b | Unknown b -> Base58.simple_encode b58check_encoding (Unknown b) include Helpers.MakeEncoder(struct @@ -448,8 +495,9 @@ include Helpers.MakeEncoder(struct let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) -let of_secp256k1 s = Secp256k1 s let of_ed25519 s = Ed25519 s +let of_secp256k1 s = Secp256k1 s +let of_p256 s = P256 s let zero = of_ed25519 Ed25519.zero @@ -463,7 +511,8 @@ let sign ?watermark secret_key message = let watermark = Option.map ~f:bytes_of_watermark watermark in match secret_key with | Secret_key.Ed25519 sk -> of_ed25519 (Ed25519.sign ?watermark sk message) - | Secret_key.Secp256k1 sk -> of_secp256k1 (Secp256k1.sign ?watermark sk message) + | Secp256k1 sk -> of_secp256k1 (Secp256k1.sign ?watermark sk message) + | P256 sk -> of_p256 (P256.sign ?watermark sk message) let check ?watermark public_key signature message = let watermark = Option.map ~f:bytes_of_watermark watermark in @@ -478,12 +527,18 @@ let check ?watermark public_key signature message = | Some s -> Secp256k1.check ?watermark pk s message | None -> false end + | Public_key.P256 pk, Unknown signature -> begin + match P256.of_bytes_opt signature with + | Some s -> P256.check ?watermark pk s message + | None -> false + end | Public_key.Ed25519 pk, Ed25519 signature -> Ed25519.check ?watermark pk signature message | Public_key.Secp256k1 pk, Secp256k1 signature -> Secp256k1.check ?watermark pk signature message - | Public_key.Ed25519 _, Secp256k1 _ -> false - | Public_key.Secp256k1 _, Ed25519 _ -> false + | Public_key.P256 pk, P256 signature -> + P256.check ?watermark pk signature message + | _ -> false let append ?watermark sk msg = MBytes.concat "" [msg; (to_bytes (sign ?watermark sk msg))] @@ -494,28 +549,34 @@ let concat msg signature = type algo = | Ed25519 | Secp256k1 + | P256 let algo_param () = Clic.parameter - ~autocomplete:(fun _ -> return [ "ed25519" ; "secp256k1" ]) + ~autocomplete:(fun _ -> return [ "ed25519" ; "secp256k1" ; "p256"]) begin fun _ name -> match name with | "ed25519" -> return Ed25519 | "secp256k1" -> return Secp256k1 + | "p256" -> return P256 | name -> failwith "Unknown signature algorithm (%s). \ - Available: 'ed25519' or 'secp256k1'" + Available: 'ed25519', 'secp256k1' or 'p256'" name end let generate_key ?(algo = Ed25519) ?seed () = match algo with - | Secp256k1 -> - let pkh, pk, sk = Secp256k1.generate_key ?seed () in - (Public_key_hash.Secp256k1 pkh, - Public_key.Secp256k1 pk, Secret_key.Secp256k1 sk) | Ed25519 -> let pkh, pk, sk = Ed25519.generate_key ?seed () in (Public_key_hash.Ed25519 pkh, Public_key.Ed25519 pk, Secret_key.Ed25519 sk) + | Secp256k1 -> + let pkh, pk, sk = Secp256k1.generate_key ?seed () in + (Public_key_hash.Secp256k1 pkh, + Public_key.Secp256k1 pk, Secret_key.Secp256k1 sk) + | P256 -> + let pkh, pk, sk = P256.generate_key ?seed () in + (Public_key_hash.P256 pkh, + Public_key.P256 pk, Secret_key.P256 sk) diff --git a/src/lib_crypto/signature.mli b/src/lib_crypto/signature.mli index acd72e308..ac20562d3 100644 --- a/src/lib_crypto/signature.mli +++ b/src/lib_crypto/signature.mli @@ -10,14 +10,17 @@ type public_key_hash = | Ed25519 of Ed25519.Public_key_hash.t | Secp256k1 of Secp256k1.Public_key_hash.t + | P256 of P256.Public_key_hash.t type public_key = | Ed25519 of Ed25519.Public_key.t | Secp256k1 of Secp256k1.Public_key.t + | P256 of P256.Public_key.t type secret_key = | Ed25519 of Ed25519.Secret_key.t | Secp256k1 of Secp256k1.Secret_key.t + | P256 of P256.Secret_key.t type watermark = | Block_header @@ -45,6 +48,7 @@ include S.RAW_DATA with type t := t type algo = | Ed25519 | Secp256k1 + | P256 val algo_param: unit -> (algo, 'a) Clic.parameter diff --git a/src/lib_crypto/tezos-crypto.opam b/src/lib_crypto/tezos-crypto.opam index aa3523f57..33b6eb736 100644 --- a/src/lib_crypto/tezos-crypto.opam +++ b/src/lib_crypto/tezos-crypto.opam @@ -19,6 +19,7 @@ depends: [ "hacl" "zarith" "secp256k1" + "uecc" "alcotest" { test & >= "0.8.3" } ] build: [ diff --git a/src/lib_protocol_environment/sigs/jbuild b/src/lib_protocol_environment/sigs/jbuild index cbd7a0664..86d7d158f 100644 --- a/src/lib_protocol_environment/sigs/jbuild +++ b/src/lib_protocol_environment/sigs/jbuild @@ -41,6 +41,7 @@ v1/blake2B.mli v1/ed25519.mli v1/secp256k1.mli + v1/p256.mli v1/signature.mli v1/block_hash.mli v1/operation_hash.mli diff --git a/src/lib_protocol_environment/sigs/v1/p256.mli b/src/lib_protocol_environment/sigs/v1/p256.mli new file mode 100644 index 000000000..c2478e609 --- /dev/null +++ b/src/lib_protocol_environment/sigs/v1/p256.mli @@ -0,0 +1,12 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +(** Tezos - P256 cryptography *) + +include S.SIGNATURE with type watermark := MBytes.t diff --git a/src/lib_protocol_environment/sigs/v1/signature.mli b/src/lib_protocol_environment/sigs/v1/signature.mli index 4b259b9bd..969a9041b 100644 --- a/src/lib_protocol_environment/sigs/v1/signature.mli +++ b/src/lib_protocol_environment/sigs/v1/signature.mli @@ -10,10 +10,12 @@ type public_key_hash = | Ed25519 of Ed25519.Public_key_hash.t | Secp256k1 of Secp256k1.Public_key_hash.t + | P256 of P256.Public_key_hash.t type public_key = | Ed25519 of Ed25519.Public_key.t | Secp256k1 of Secp256k1.Public_key.t + | P256 of P256.Public_key.t type watermark = | Block_header diff --git a/src/lib_protocol_environment/tezos_protocol_environment.ml b/src/lib_protocol_environment/tezos_protocol_environment.ml index 096b7ff54..63d6214d0 100644 --- a/src/lib_protocol_environment/tezos_protocol_environment.ml +++ b/src/lib_protocol_environment/tezos_protocol_environment.ml @@ -148,6 +148,9 @@ module Make (Context : CONTEXT) = struct and type Secp256k1.Public_key_hash.t = Secp256k1.Public_key_hash.t and type Secp256k1.Public_key.t = Secp256k1.Public_key.t and type Secp256k1.t = Secp256k1.t + and type P256.Public_key_hash.t = P256.Public_key_hash.t + and type P256.Public_key.t = P256.Public_key.t + and type P256.t = P256.t and type Signature.public_key_hash = Signature.public_key_hash and type Signature.public_key = Signature.public_key and type Signature.t = Signature.t @@ -232,6 +235,7 @@ module Make (Context : CONTEXT) = struct module Time = Time module Ed25519 = Ed25519 module Secp256k1 = Secp256k1 + module P256 = P256 module Signature = Signature module S = struct module type T = Tezos_base.S.T diff --git a/src/lib_protocol_environment/tezos_protocol_environment.mli b/src/lib_protocol_environment/tezos_protocol_environment.mli index 64cf178cd..faa538df4 100644 --- a/src/lib_protocol_environment/tezos_protocol_environment.mli +++ b/src/lib_protocol_environment/tezos_protocol_environment.mli @@ -141,6 +141,9 @@ module Make (Context : CONTEXT) : sig and type Secp256k1.Public_key_hash.t = Secp256k1.Public_key_hash.t and type Secp256k1.Public_key.t = Secp256k1.Public_key.t and type Secp256k1.t = Secp256k1.t + and type P256.Public_key_hash.t = P256.Public_key_hash.t + and type P256.Public_key.t = P256.Public_key.t + and type P256.t = P256.t and type Signature.public_key_hash = Signature.public_key_hash and type Signature.public_key = Signature.public_key and type Signature.t = Signature.t diff --git a/src/proto_alpha/lib_protocol/src/contract_repr.ml b/src/proto_alpha/lib_protocol/src/contract_repr.ml index d4bd7ae27..2c0fea3a4 100644 --- a/src/proto_alpha/lib_protocol/src/contract_repr.ml +++ b/src/proto_alpha/lib_protocol/src/contract_repr.ml @@ -35,6 +35,7 @@ let of_b58check s = match Base58.decode s with | Some (Ed25519.Public_key_hash.Data h) -> ok (Implicit (Signature.Ed25519 h)) | Some (Secp256k1.Public_key_hash.Data h) -> ok (Implicit (Signature.Secp256k1 h)) + | Some (P256.Public_key_hash.Data h) -> ok (Implicit (Signature.P256 h)) | Some (Contract_hash.Data h) -> ok (Originated h) | _ -> error (Invalid_contract_notation s) @@ -184,6 +185,9 @@ module Index = struct Ed25519.Public_key_hash.prefix_path s let pkh_prefix_secp256k1 s = Secp256k1.Public_key_hash.prefix_path s + let pkh_prefix_p256 s = + P256.Public_key_hash.prefix_path s + let rpc_arg = rpc_arg let encoding = encoding let compare = compare diff --git a/src/proto_alpha/lib_protocol/src/contract_repr.mli b/src/proto_alpha/lib_protocol/src/contract_repr.mli index d55f049e3..1ff7ae58e 100644 --- a/src/proto_alpha/lib_protocol/src/contract_repr.mli +++ b/src/proto_alpha/lib_protocol/src/contract_repr.mli @@ -65,4 +65,5 @@ module Index : sig val contract_prefix: string -> string list val pkh_prefix_ed25519: string -> string list val pkh_prefix_secp256k1: string -> string list + val pkh_prefix_p256: string -> string list end diff --git a/src/proto_alpha/lib_protocol/src/storage.ml b/src/proto_alpha/lib_protocol/src/storage.ml index 810ca8749..568eaa832 100644 --- a/src/proto_alpha/lib_protocol/src/storage.ml +++ b/src/proto_alpha/lib_protocol/src/storage.ml @@ -536,4 +536,15 @@ let () = | Contract_repr.Implicit (Secp256k1 pkh) -> pkh | Contract_repr.Implicit _ -> assert false | Contract_repr.Originated _ -> assert false) + l) ; + Raw_context.register_resolvers + P256.Public_key_hash.b58check_encoding + (fun ctxt p -> + let p = Contract_repr.Index.pkh_prefix_p256 p in + Contract.Indexed_context.resolve ctxt p >|= fun l -> + List.map + (function + | Contract_repr.Implicit (P256 pkh) -> pkh + | Contract_repr.Implicit _ -> assert false + | Contract_repr.Originated _ -> assert false) l)