packages feed

cryptol-2.10.0: lib/PrimeEC.cry

module PrimeEC where

/**
 * The type of points of an elliptic curve in affine coordinates.
 * The coefficients are taken from the prime field 'Z p' with 'p > 3'.
 * This is intended to represent all the "normal" points
 * on the curve, which satisfy 'x^^3 == y^^2 - 3x + b', 
 * for some curve parameter 'b'.  This type cannot represent
 * the special projective "point at infinity".
 */
type AffinePoint p =
  { x : Z p
  , y : Z p
  }

/**
 * The type of points of an elliptic curve in (homogeneous)
 * projective coordinates.  The coefficients are taken from the
 * prime field 'Z p' with 'p > 3'. These points should be understood as
 * representatives of equivalence classes of points, where two representatives
 * 'S' and 'T' are equivalent iff one is a scalar multiple of the other. That
 * is, 'S' and 'T' are equivalent iff there exists some 'k' where
 * 'S.x == k*T.x /\ S.y == k*T.y /\ S.z == k*T.z'.  Finally, the
 * vector with all coordinates equal to 0 is excluded and does not
 * represent any point.
 *
 * Note that all the affine points are easily embedded into projective
 * coordinates by simply setting the `z` coordinate to 1, and the "point at
 * infinity" is represented by any point with 'z == 0'.  Further, for any
 * projective point with 'z != 0', we can compute the corresponding affine
 * point by simply multiplying the x and y coordinates by the inverse of z.
 */
type ProjectivePoint p =
  { x : Z p
  , y : Z p
  , z : Z p
  }

/**
 * 'ec_is_point_affine b S' checks that the supposed affine elliptic curve
 * point 'S' in fact lies on the curve defined by the curve parameter 'b'.  Here,
 * and throughout this module, we assume the curve parameter 'a' is equal to
 * '-3'.  Precisely, this function checks the following condition:
 *
 *     S.y^^2 == S.x^^3 - 3*S.x + b
 */
ec_is_point_affine : {p} (prime p, p > 3) => Z p -> AffinePoint p -> Bit
ec_is_point_affine b S = S.y^^2 == S.x^^3 - (3*S.x) + b


/**
 * 'ec_is_nonsingular' checks that the given curve parameter 'b' gives rise to
 * a non-singular elliptic curve, appropriate for use in ECC.
 *
 * Precisely, this checks that '4*a^^3 + 27*b^^2 != 0 mod p'.  Here, and
 * throughout this module, we assume 'a = -3'.
 */
ec_is_nonsingular : {p} (prime p, p > 3) => Z p -> Bit
ec_is_nonsingular b = (fromInteger 4) * a^^3 + (fromInteger 27) * b^^2 != 0
  where a = -3 : Z p

/**
 * Returns true if the given point is the identity "point at infinity."
 * This is true whenever the 'z' coordinate is 0, but one of the 'x' or
 * 'y' coordinates is nonzero.
 */
ec_is_identity : {p} (prime p, p > 3) => ProjectivePoint p -> Bit
ec_is_identity S = S.z == 0 /\ ~(S.x == 0 /\ S.y == 0)

/**
 * Test two projective points for equality, up to the equivalence relation
 * on projective points.
 */
ec_equal : {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p -> Bit
ec_equal S T =
  (S.z == 0 /\ T.z == 0) \/
  (S.z != 0 /\ T.z != 0 /\ ec_affinify S == ec_affinify T)

/**
 * Compute a projective representative for the given affine point.
 */
ec_projectify : {p} (prime p, p > 3) => AffinePoint p -> ProjectivePoint p
ec_projectify R = { x = R.x, y = R.y, z = 1 }

/**
 * Compute the affine point corresponding to the given projective point.
 * This results in an error if the 'z' component of the given point is 0,
 * in which case there is no corresponding affine point.
 */
ec_affinify : {p} (prime p, p > 3) => ProjectivePoint p -> AffinePoint p
ec_affinify S =
 if S.z == 0 then error "Cannot affinify the point at infinity" else R
    where
      R = {x = lambda^^2 * S.x, y = lambda^^3 * S.y }
      lambda = recip S.z

/**
 * Coerce an integer modulo 'p' to a bitvector. This will reduce the value
 * modulo '2^^a' if necessary.
 */
ZtoBV : {p, a} (fin p, p >= 1, fin a) => Z p -> [a]
ZtoBV x = fromInteger (fromZ x)

/**
 * Coerce a bitvector value to an integer modulo 'p'.  This will
 * reduce the value modulo 'p' if necessary.
 */
BVtoZ : {p, a} (fin p, p >= 1, fin a) => [a] -> Z p
BVtoZ x = fromInteger (toInteger x)

/**
 * Given a projective point 'S', compute '2S = S+S'.
 */
primitive ec_double : {p} (prime p, p > 3) =>
  ProjectivePoint p -> ProjectivePoint p

/**
 * Given two projective points 'S' and 'T' where neither is the identity,
 * compute 'S+T'. If the points are not known to be distinct from the point
 * at infinity, use 'ec_add' instead.
 */
primitive ec_add_nonzero : {p} (prime p, p > 3) =>
  ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p

/**
 * Given a projective point 'S', compute its negation, '-S'
 */
ec_negate : {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p
ec_negate S = { x = S.x, y = -S.y, z = S.z }

/**
 * Given two projective points 'S' and 'T' compute 'S+T'.
 */
ec_add : {p} (prime p, p > 3) =>
  ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p
ec_add S T =
  if S.z == 0 then T
   | T.z == 0 then S
   else R
 where R = ec_add_nonzero S T

/**
 * Given two projective points 'S' and 'T' compute 'S-T'.
 */
ec_sub : {p} (prime p, p > 3) =>
  ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p
ec_sub S T = ec_add S U
 where U = { x = T.x, y = -T.y, z = T.z }

/**
 * Given a scalar value 'k' and a projective point 'S', compute the
 * scalar multiplication 'kS'.
 */
primitive ec_mult : {p} (prime p, p > 3) =>
  Z p -> ProjectivePoint p -> ProjectivePoint p

/**
 * Given a scalar value 'j' and a projective point 'S', and another scalar
 * value 'k' and point 'T', compute the "twin" scalar multiplication 'jS + kT'.
 */
primitive ec_twin_mult : {p} (prime p, p > 3) =>
  Z p -> ProjectivePoint p -> Z p -> ProjectivePoint p -> ProjectivePoint p