281 lines
8.7 KiB
OCaml
281 lines
8.7 KiB
OCaml
(*****************************************************************************)
|
|
(* *)
|
|
(* Open Source License *)
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
(* *)
|
|
(* Permission is hereby granted, free of charge, to any person obtaining a *)
|
|
(* copy of this software and associated documentation files (the "Software"),*)
|
|
(* to deal in the Software without restriction, including without limitation *)
|
|
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
|
|
(* and/or sell copies of the Software, and to permit persons to whom the *)
|
|
(* Software is furnished to do so, subject to the following conditions: *)
|
|
(* *)
|
|
(* The above copyright notice and this permission notice shall be included *)
|
|
(* in all copies or substantial portions of the Software. *)
|
|
(* *)
|
|
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
|
|
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
|
|
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
|
|
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
|
|
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
|
|
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
|
|
(* DEALINGS IN THE SOFTWARE. *)
|
|
(* *)
|
|
(*****************************************************************************)
|
|
|
|
module Sp = Libsecp256k1.Internal
|
|
|
|
module type SCALAR_SIG = sig
|
|
type t
|
|
include S.B58_DATA with type t := t
|
|
include S.ENCODER with type t := t
|
|
val zero : t
|
|
val one : t
|
|
val of_Z : Z.t -> t
|
|
val to_Z : t -> Z.t
|
|
val of_int : int -> t
|
|
val add: t -> t -> t
|
|
val mul: t -> t -> t
|
|
val negate: t -> t
|
|
val sub : t -> t -> t
|
|
val of_bits_exn: string -> t
|
|
val to_bits: t -> string
|
|
val inverse: t -> t option
|
|
val pow: t -> Z.t -> t
|
|
val equal : t -> t -> bool
|
|
end
|
|
|
|
module Group : sig
|
|
val order: Z.t
|
|
module Scalar : SCALAR_SIG
|
|
type t
|
|
include S.B58_DATA with type t := t
|
|
include S.ENCODER with type t := t
|
|
val e: t
|
|
val g: t
|
|
val h: t
|
|
val of_coordinates: x:Z.t -> y:Z.t -> t
|
|
val of_bits_exn: string -> t
|
|
val to_bits: t -> string
|
|
val mul: Scalar.t -> t -> t
|
|
val (+): t -> t -> t
|
|
val (-): t -> t -> t
|
|
val (=): t -> t -> bool
|
|
end = struct
|
|
|
|
let order = Z.of_string_base 16 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
|
|
|
|
let string_rev s =
|
|
let len = String.length s in
|
|
String.init len (fun i -> s.[len - 1 - i])
|
|
|
|
let b32_of_Z z =
|
|
let cs = Cstruct.create 32 in
|
|
let bits = Z.to_bits z in
|
|
let length = (min 32 (String.length bits)) in
|
|
let bits = String.sub bits 0 length in
|
|
let bits = string_rev bits in
|
|
Cstruct.blit_from_string bits 0 cs (32 - length) length;
|
|
cs
|
|
|
|
let z_of_b32 b =
|
|
b |> Cstruct.to_string |> string_rev |> Z.of_bits
|
|
|
|
module Scalar : SCALAR_SIG with type t = Sp.Scalar.t = struct
|
|
type t = Sp.Scalar.t
|
|
|
|
let zero = Sp.Scalar.zero ()
|
|
let one = Sp.Scalar.one ()
|
|
let equal x y = Sp.Scalar.equal x y
|
|
|
|
|
|
let of_Z z =
|
|
let z = Z.erem z order in
|
|
let r = Sp.Scalar.const () in
|
|
let cs = b32_of_Z z in
|
|
let _ = Sp.Scalar.set_b32 r cs in r
|
|
|
|
let to_Z s =
|
|
let cs = Cstruct.create 32 in
|
|
Sp.Scalar.get_b32 cs s; cs |> z_of_b32
|
|
|
|
let of_int i = i |> Z.of_int |> of_Z
|
|
|
|
let pow t n =
|
|
Z.powm (to_Z t) n order |> of_Z
|
|
|
|
let add x y =
|
|
let r = Sp.Scalar.const () in
|
|
let _ = Sp.Scalar.add r x y in r
|
|
|
|
let mul x y =
|
|
let r = Sp.Scalar.const () in
|
|
Sp.Scalar.mul r x y; r
|
|
|
|
let negate x =
|
|
let r = Sp.Scalar.const () in
|
|
Sp.Scalar.negate r x; r
|
|
|
|
let sub x y =
|
|
add x (negate y)
|
|
|
|
let of_bits_exn bits =
|
|
let r = Sp.Scalar.const () in
|
|
(* trim to 32 bytes *)
|
|
let cs = Cstruct.create 32 in
|
|
Cstruct.blit_from_string bits 0 cs 0 (min (String.length bits) 32);
|
|
(* ignore overflow condition, it's always 0 based on the c-code *)
|
|
let _ = Sp.Scalar.set_b32 r cs in r
|
|
|
|
(* TODO, check that we are less than the order *)
|
|
|
|
let to_bits x =
|
|
let c = Cstruct.create 32 in
|
|
Sp.Scalar.get_b32 c x; Cstruct.to_string c
|
|
|
|
let inverse x =
|
|
if x = zero then
|
|
None else
|
|
let r = Sp.Scalar.const () in
|
|
Sp.Scalar.inverse r x; Some r
|
|
|
|
type Base58.data +=
|
|
| Data of t
|
|
|
|
let b58check_encoding =
|
|
Base58.register_encoding
|
|
~prefix: Base58.Prefix.secp256k1_scalar
|
|
~length: 32
|
|
~to_raw: to_bits
|
|
~of_raw: (fun s -> try Some (of_bits_exn s) with _ -> None)
|
|
~wrap: (fun x -> Data x)
|
|
|
|
let title = "Secp256k1_group.Scalar"
|
|
let name = "Anscalar for the secp256k1 group"
|
|
|
|
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 = Data_encoding.(conv to_bits of_bits_exn string)
|
|
let to_b58check = to_b58check
|
|
let to_short_b58check = to_short_b58check
|
|
let of_b58check = of_b58check
|
|
let of_b58check_opt = of_b58check_opt
|
|
let of_b58check_exn = of_b58check_exn
|
|
end)
|
|
end
|
|
|
|
type t = Sp.Group.Jacobian.t
|
|
(* type ge = Sp.Group.ge *)
|
|
|
|
let field_of_Z z =
|
|
let fe = Sp.Field.const () in
|
|
let cs = b32_of_Z z in
|
|
let _ = Sp.Field.set_b32 fe cs in fe
|
|
|
|
let group_of_jacobian j =
|
|
let r = Sp.Group.of_fields () in
|
|
Sp.Group.Jacobian.get_ge r j; r
|
|
|
|
let jacobian_of_group g =
|
|
let j = Sp.Group.Jacobian.of_fields () in
|
|
Sp.Group.Jacobian.set_ge j g; j
|
|
|
|
|
|
let of_coordinates ~x ~y =
|
|
Sp.Group.of_fields
|
|
~x:(field_of_Z x) ~y:(field_of_Z y) () |> jacobian_of_group
|
|
|
|
let e =
|
|
Sp.Group.Jacobian.of_fields ~infinity:true ()
|
|
|
|
let g =
|
|
let gx = Z.of_string "55066263022277343669578718895168534326250603453777594175500187360389116729240"
|
|
and gy = Z.of_string "32670510020758816978083085130507043184471273380659243275938904335757337482424" in
|
|
of_coordinates ~x:gx ~y:gy
|
|
|
|
(* To obtain the second generator, take the sha256 hash of the decimal representation of g1_y
|
|
python -c "import hashlib;print int(hashlib.sha256('32670510020758816978083085130507043184471273380659243275938904335757337482424').hexdigest(),16)"
|
|
*)
|
|
let h =
|
|
let hx = Z.of_string "54850469061264194188802857211425616972714231399857248865148107587305936171824"
|
|
and hy = Z.of_string "6558914719042992724977242403721980463337660510165027616783569279181206179101" in
|
|
of_coordinates ~x:hx ~y:hy
|
|
|
|
let (+) x y =
|
|
let r = Sp.Group.Jacobian.of_fields () in
|
|
Sp.Group.Jacobian.add_var r x y; r
|
|
|
|
let (-) x y =
|
|
let neg_y = Sp.Group.Jacobian.of_fields () in
|
|
Sp.Group.Jacobian.neg neg_y y; x + neg_y
|
|
|
|
let (=) x y = Sp.Group.Jacobian.is_infinity (x - y)
|
|
|
|
let mul s g =
|
|
let r = Sp.Group.Jacobian.of_fields () in
|
|
Sp.Group.Jacobian.mul r (group_of_jacobian g) s; r
|
|
|
|
let to_bits j =
|
|
let x = group_of_jacobian j
|
|
and buf = Cstruct.create 33 in
|
|
let cs = (Sp.Group.to_pubkey ~compress:true buf x) in
|
|
Cstruct.to_string cs
|
|
|
|
let of_bits_exn bits =
|
|
let buf = Cstruct.of_string bits
|
|
and x = Sp.Group.of_fields () in
|
|
Sp.Group.from_pubkey x buf;
|
|
x |> jacobian_of_group
|
|
|
|
|
|
module Encoding = struct
|
|
type Base58.data +=
|
|
| Data of t
|
|
|
|
let title = "Secp256k1_group.Group"
|
|
let name = "An element of secp256k1"
|
|
|
|
let b58check_encoding =
|
|
Base58.register_encoding
|
|
~prefix: Base58.Prefix.secp256k1_element
|
|
~length: 33
|
|
~to_raw: to_bits
|
|
~of_raw: (fun s -> try Some (of_bits_exn s) with _ -> None)
|
|
~wrap: (fun x -> Data x)
|
|
|
|
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 = Data_encoding.(conv to_bits of_bits_exn string)
|
|
let to_b58check = to_b58check
|
|
let to_short_b58check = to_short_b58check
|
|
let of_b58check = of_b58check
|
|
let of_b58check_opt = of_b58check_opt
|
|
let of_b58check_exn = of_b58check_exn
|
|
end
|
|
)
|
|
end
|
|
|
|
include Encoding
|
|
|
|
end
|