···6565 module Precompute : sig
6666 val generator_tables : unit -> string array array array
6767 end
6868-end
69687070-module type Point = sig
7171- type point
7272- type scalar
7373-7474- val of_octets : string -> (point, error) result
7575- val to_octets : ?compress:bool -> point -> string
7676- val scalar_of_octets : string -> (scalar, error) result
7777- val scalar_to_octets : scalar -> string
7878- val generator : point
7979- val add : point -> point -> point
8080- val scalar_mult : scalar -> point -> point
6969+ module Primitive : sig
7070+ val generator : pub
7171+ val add : pub -> pub -> pub
7272+ val scalar_mult : priv -> pub -> pub
7373+ end
8174end
82758376module type Dh_dsa = sig
8477 module Dh : Dh
8578 module Dsa : Dsa
8686- module Point : Point
8779end
88808981type field_element = string
···776768 module Precompute = struct
777769 let generator_tables = S.generator_tables
778770 end
779779-end
780771781781-module Make_point (P : Point_ops) (S : Scalar) :
782782- Point with type point = point and type scalar = scalar = struct
783783- type nonrec point = point
784784- type nonrec scalar = scalar
785785-786786- let of_octets = P.of_octets
787787- let to_octets ?(compress = false) p = P.to_octets ~compress p
788788- let scalar_of_octets = S.of_octets
789789- let scalar_to_octets = S.to_octets
790790- let generator = P.params_g
791791- let add = P.add
792792- let scalar_mult = S.scalar_mult
772772+ module Primitive = struct
773773+ let generator = P.params_g
774774+ let add = P.add
775775+ let scalar_mult = S.scalar_mult
776776+ end
793777end
794778795779module P256 : Dh_dsa = struct
···910894 module Dh = Make_dh (Params) (P) (S)
911895 module Fn = Make_Fn (Params) (Foreign_n)
912896 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA256)
913913- module Point = Make_point (P) (S)
914897end
915898916899module P384 : Dh_dsa = struct
···10311014 module Dh = Make_dh (Params) (P) (S)
10321015 module Fn = Make_Fn (Params) (Foreign_n)
10331016 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA384)
10341034- module Point = Make_point (P) (S)
10351017end
1036101810371019module P521 : Dh_dsa = struct
···11561138 module Dh = Make_dh (Params) (P) (S)
11571139 module Fn = Make_Fn (Params) (Foreign_n)
11581140 module Dsa = Make_dsa (Params) (Fn) (P) (S) (Digestif.SHA512)
11591159- module Point = Make_point (P) (S)
11601141end
1161114211621143module X25519 = struct
+9-33
ec/crypto_ec.mli
···147147 the generator point for the curve. Useful only to bootstrap tables
148148 necessary for scalar multiplication. *)
149149 end
150150-end
151150152152-(** Low-level point arithmetic. *)
153153-module type Point = sig
154154- type point
155155- (** The type for points on the elliptic curve. *)
156156-157157- type scalar
158158- (** The type for scalars. *)
159159-160160- val of_octets : string -> (point, error) result
161161- (** [of_octets buf] decodes a point from [buf] in uncompressed or compressed
162162- SEC 1 format. Returns an error if the point is not on the curve. *)
163163-164164- val to_octets : ?compress:bool -> point -> string
165165- (** [to_octets ~compress point] encodes [point] to SEC 1 format. If [compress]
166166- is [true] (default [false]), the compressed format is used. *)
167167-168168- val scalar_of_octets : string -> (scalar, error) result
169169- (** [scalar_of_octets buf] decodes a scalar from [buf]. Returns an error if
170170- the scalar is not in the valid range \[1, n-1\] where n is the group
171171- order. *)
151151+ (** {2 Primitive operations} *)
172152173173- val scalar_to_octets : scalar -> string
174174- (** [scalar_to_octets scalar] encodes [scalar] to a byte string. *)
153153+ module Primitive : sig
154154+ val generator : pub
155155+ (** [generator] is the generator point (base point) of the curve. *)
175156176176- val generator : point
177177- (** [generator] is the generator point (base point) of the curve. *)
157157+ val add : pub -> pub -> pub
158158+ (** [add p q] is the sum of points [p] and [q]. *)
178159179179- val add : point -> point -> point
180180- (** [add p q] is the sum of points [p] and [q]. *)
181181-182182- val scalar_mult : scalar -> point -> point
183183- (** [scalar_mult s p] is the scalar multiplication of [p] by [s]. *)
160160+ val scalar_mult : priv -> pub -> pub
161161+ (** [scalar_mult s p] is the scalar multiplication of [p] by [s]. *)
162162+ end
184163end
185164186165(** Elliptic curve with Diffie-Hellman and DSA. *)
···190169191170 module Dsa : Dsa
192171 (** Digital signature algorithm. *)
193193-194194- module Point : Point
195195- (** Low-level point arithmetic. *)
196172end
197173198174module P256 : Dh_dsa
+30-32
test/test_crypto_ec.ml
···999999 let open C in
10001000 let test_generator_not_identity () =
10011001 (* Generator should not be the identity (at infinity) *)
10021002- let g = Point.generator in
10031003- let g_bytes = Point.to_octets g in
10021002+ let g = Dsa.Primitive.generator in
10031003+ let g_bytes = Dsa.pub_to_octets g in
10041004 (* Generator serialized should not be just the identity point *)
10051005 Alcotest.(check bool)
10061006 "generator has non-trivial encoding" true
10071007 (String.length g_bytes > 1)
10081008 in
10091009 let test_point_serialization_roundtrip () =
10101010- (* Generate a key pair and check that the public key roundtrips through Point *)
10101010+ (* Generate a key pair and check that the public key roundtrips *)
10111011 let _priv, pub = Dsa.generate () in
10121012 let pub_bytes = Dsa.pub_to_octets pub in
10131013- match Point.of_octets pub_bytes with
10131013+ match Dsa.pub_of_octets pub_bytes with
10141014 | Ok point ->
10151015- let point_bytes = Point.to_octets point in
10151015+ let point_bytes = Dsa.pub_to_octets point in
10161016 Alcotest.(check string) "point roundtrip" pub_bytes point_bytes
10171017- | Error e -> Alcotest.failf "of_octets failed: %a" pp_error e
10171017+ | Error e -> Alcotest.failf "pub_of_octets failed: %a" pp_error e
10181018 in
10191019 let test_point_compressed_serialization () =
10201020 let _priv, pub = Dsa.generate () in
10211021 let pub_bytes = Dsa.pub_to_octets pub in
10221022- match Point.of_octets pub_bytes with
10221022+ match Dsa.pub_of_octets pub_bytes with
10231023 | Ok point -> (
10241024- let compressed = Point.to_octets ~compress:true point in
10241024+ let compressed = Dsa.pub_to_octets ~compress:true point in
10251025 (* Compressed form should be shorter *)
10261026 Alcotest.(check bool)
10271027 "compressed is shorter" true
10281028 (String.length compressed < String.length pub_bytes);
10291029 (* Should be able to decode compressed form *)
10301030- match Point.of_octets compressed with
10301030+ match Dsa.pub_of_octets compressed with
10311031 | Ok point' ->
10321032- let uncompressed = Point.to_octets point' in
10321032+ let uncompressed = Dsa.pub_to_octets point' in
10331033 Alcotest.(check string)
10341034 "compressed roundtrip" pub_bytes uncompressed
10351035- | Error e -> Alcotest.failf "compressed of_octets failed: %a" pp_error e
10361036- )
10371037- | Error e -> Alcotest.failf "of_octets failed: %a" pp_error e
10351035+ | Error e ->
10361036+ Alcotest.failf "compressed pub_of_octets failed: %a" pp_error e)
10371037+ | Error e -> Alcotest.failf "pub_of_octets failed: %a" pp_error e
10381038 in
10391039 let test_scalar_serialization_roundtrip () =
10401040 (* Generate a key and check scalar roundtrip *)
10411041- let secret, _pub = Dh.gen_key () in
10421042- let secret_bytes = Dh.secret_to_octets secret in
10431043- match Point.scalar_of_octets secret_bytes with
10411041+ let priv, _pub = Dsa.generate () in
10421042+ let priv_bytes = Dsa.priv_to_octets priv in
10431043+ match Dsa.priv_of_octets priv_bytes with
10441044 | Ok scalar ->
10451045- let scalar_bytes = Point.scalar_to_octets scalar in
10461046- Alcotest.(check string) "scalar roundtrip" secret_bytes scalar_bytes
10471047- | Error e -> Alcotest.failf "scalar_of_octets failed: %a" pp_error e
10451045+ let scalar_bytes = Dsa.priv_to_octets scalar in
10461046+ Alcotest.(check string) "scalar roundtrip" priv_bytes scalar_bytes
10471047+ | Error e -> Alcotest.failf "priv_of_octets failed: %a" pp_error e
10481048 in
10491049 let test_scalar_mult_with_generator () =
10501050 (* scalar_mult with generator should give the same result as pub_of_priv *)
10511051 let priv, pub = Dsa.generate () in
10521052- let priv_bytes = Dsa.priv_to_octets priv in
10531052 let pub_bytes = Dsa.pub_to_octets pub in
10541054- match Point.scalar_of_octets priv_bytes with
10551055- | Ok scalar ->
10561056- let computed_pub = Point.scalar_mult scalar Point.generator in
10571057- let computed_bytes = Point.to_octets computed_pub in
10581058- Alcotest.(check string) "scalar_mult generator" pub_bytes computed_bytes
10591059- | Error e -> Alcotest.failf "scalar_of_octets failed: %a" pp_error e
10531053+ let computed_pub = Dsa.Primitive.scalar_mult priv Dsa.Primitive.generator in
10541054+ let computed_bytes = Dsa.pub_to_octets computed_pub in
10551055+ Alcotest.(check string) "scalar_mult generator" pub_bytes computed_bytes
10601056 in
10611057 let test_point_add () =
10621058 (* Test that P + P = 2P (scalar_mult 2 P) *)
10631063- let g = Point.generator in
10641064- let g_plus_g = Point.add g g in
10591059+ let g = Dsa.Primitive.generator in
10601060+ let g_plus_g = Dsa.Primitive.add g g in
10651061 (* scalar 2 in big-endian encoding *)
10661062 let two =
10671063 let buf = Bytes.make Dsa.byte_length '\000' in
10681064 Bytes.set_uint8 buf (Dsa.byte_length - 1) 2;
10691065 Bytes.to_string buf
10701066 in
10711071- match Point.scalar_of_octets two with
10671067+ match Dsa.priv_of_octets two with
10721068 | Ok scalar_2 ->
10731073- let two_g = Point.scalar_mult scalar_2 g in
10691069+ let two_g = Dsa.Primitive.scalar_mult scalar_2 g in
10741070 Alcotest.(check string)
10751075- "G + G = 2G" (Point.to_octets g_plus_g) (Point.to_octets two_g)
10761076- | Error e -> Alcotest.failf "scalar_of_octets 2 failed: %a" pp_error e
10711071+ "G + G = 2G"
10721072+ (Dsa.pub_to_octets g_plus_g)
10731073+ (Dsa.pub_to_octets two_g)
10741074+ | Error e -> Alcotest.failf "priv_of_octets 2 failed: %a" pp_error e
10771075 in
10781076 [
10791077 (name ^ " Point generator", `Quick, test_generator_not_identity);