1f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be 3f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// found in the LICENSE file. 4f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 5f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// This is an implementation of the P224 elliptic curve group. It's written to 6f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// be short and simple rather than fast, although it's still constant-time. 7f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 8f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. 9f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 10f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "crypto/p224.h" 11f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 1224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <stddef.h> 1324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko#include <stdint.h> 14f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <string.h> 15f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 16f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/sys_byteorder.h" 17f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 18f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace { 19f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 20f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkousing base::HostToNet32; 21f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkousing base::NetToHost32; 22f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 23f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Field element functions. 24f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 25f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1. 26f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 27f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Field elements are represented by a FieldElement, which is a typedef to an 2824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko// array of 8 uint32_t's. The value of a FieldElement, a, is: 29f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7] 30f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 31f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Using 28-bit limbs means that there's only 4 bits of headroom, which is less 32f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// than we would really like. But it has the useful feature that we hit 2**224 33f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// exactly, making the reflections during a reduce much nicer. 34f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 35f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkousing crypto::p224::FieldElement; 36f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 37f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// kP is the P224 prime. 38f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoconst FieldElement kP = { 39f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 1, 0, 0, 268431360, 40f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 268435455, 268435455, 268435455, 268435455, 41f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 42f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 43f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Contract(FieldElement* inout); 44f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 45f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise. 4624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkouint32_t IsZero(const FieldElement& a) { 47f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement minimal; 48f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memcpy(&minimal, &a, sizeof(minimal)); 49f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Contract(&minimal); 50f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 5124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t is_zero = 0, is_p = 0; 52f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (unsigned i = 0; i < 8; i++) { 53f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= minimal[i]; 54f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= minimal[i] - kP[i]; 55f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 56f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 57f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If either is_zero or is_p is 0, then we should return 1. 58f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= is_zero >> 16; 59f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= is_zero >> 8; 60f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= is_zero >> 4; 61f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= is_zero >> 2; 62f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero |= is_zero >> 1; 63f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 64f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= is_p >> 16; 65f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= is_p >> 8; 66f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= is_p >> 4; 67f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= is_p >> 2; 68f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_p |= is_p >> 1; 69f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 70f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // For is_zero and is_p, the LSB is 0 iff all the bits are zero. 71f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero &= is_p & 1; 72f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko is_zero = (~is_zero) << 31; 7324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko is_zero = static_cast<int32_t>(is_zero) >> 31; 74f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return is_zero; 75f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 76f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 77f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Add computes *out = a+b 78f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 79f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// a[i] + b[i] < 2**32 80f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Add(FieldElement* out, const FieldElement& a, const FieldElement& b) { 81f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 82f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (*out)[i] = a[i] + b[i]; 83f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 84f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 85f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 8624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint32_t kTwo31p3 = (1u << 31) + (1u << 3); 8724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint32_t kTwo31m3 = (1u << 31) - (1u << 3); 8824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint32_t kTwo31m15m3 = (1u << 31) - (1u << 15) - (1u << 3); 89f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can 90f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// subtract smaller amounts without underflow. See the section "Subtraction" in 91f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// [1] for why. 92f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkostatic const FieldElement kZero31ModP = { 93f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko kTwo31p3, kTwo31m3, kTwo31m3, kTwo31m15m3, 94f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko kTwo31m3, kTwo31m3, kTwo31m3, kTwo31m3 95f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 96f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 97f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Subtract computes *out = a-b 98f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 99f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// a[i], b[i] < 2**30 100f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// out[i] < 2**32 101f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Subtract(FieldElement* out, const FieldElement& a, const FieldElement& b) { 102f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 103f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // See the section on "Subtraction" in [1] for details. 104f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (*out)[i] = a[i] + kZero31ModP[i] - b[i]; 105f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 106f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 107f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 10824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint64_t kTwo63p35 = (1ull << 63) + (1ull << 35); 10924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint64_t kTwo63m35 = (1ull << 63) - (1ull << 35); 11024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint64_t kTwo63m35m19 = (1ull << 63) - (1ull << 35) - (1ull << 19); 111f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section 112f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// "Subtraction" in [1] for why. 11324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint64_t kZero63ModP[8] = { 11424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35, 11524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35, 116f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 117f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 11824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkostatic const uint32_t kBottom28Bits = 0xfffffff; 119f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 120f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// LargeFieldElement also represents an element of the field. The limbs are 121f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// still spaced 28-bits apart and in little-endian order. So the limbs are at 122f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 0, 28, 56, ..., 392 bits, each 64-bits wide. 12324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkotypedef uint64_t LargeFieldElement[15]; 124f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 125f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ReduceLarge converts a LargeFieldElement to a FieldElement. 126f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 127f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// in[i] < 2**62 128f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid ReduceLarge(FieldElement* out, LargeFieldElement* inptr) { 129f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko LargeFieldElement& in(*inptr); 130f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 131f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 132f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[i] += kZero63ModP[i]; 133f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 134f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 135f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Eliminate the coefficients at 2**224 and greater while maintaining the 136f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // same value mod p. 137f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 14; i >= 8; i--) { 138f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[i-8] -= in[i]; // reflection off the "+1" term of p. 139f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[i-5] += (in[i] & 0xffff) << 12; // part of the "-2**96" reflection. 140f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[i-4] += in[i] >> 16; // the rest of the "-2**96" reflection. 141f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 142f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[8] = 0; 143f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // in[0..8] < 2**64 144f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 145f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // As the values become small enough, we start to store them in |out| and use 146f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 32-bit operations. 147f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 1; i < 8; i++) { 148f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[i+1] += in[i] >> 28; 14924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[i] = static_cast<uint32_t>(in[i] & kBottom28Bits); 150f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 151f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Eliminate the term at 2*224 that we introduced while keeping the same 152f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // value mod p. 153f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko in[0] -= in[8]; // reflection off the "+1" term of p. 15424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[3] += static_cast<uint32_t>(in[8] & 0xffff) << 12; // "-2**96" term 15524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[4] += static_cast<uint32_t>(in[8] >> 16); // rest of "-2**96" term 156f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // in[0] < 2**64 157f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[3] < 2**29 158f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[4] < 2**29 159f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[1,2,5..7] < 2**28 160f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 16124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[0] = static_cast<uint32_t>(in[0] & kBottom28Bits); 16224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[1] += static_cast<uint32_t>((in[0] >> 28) & kBottom28Bits); 16324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko (*out)[2] += static_cast<uint32_t>(in[0] >> 56); 164f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[0] < 2**28 165f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[1..4] < 2**29 166f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[5..7] < 2**28 167f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 168f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 169f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Mul computes *out = a*b 170f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 171f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// a[i] < 2**29, b[i] < 2**30 (or vice versa) 172f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// out[i] < 2**29 173f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Mul(FieldElement* out, const FieldElement& a, const FieldElement& b) { 174f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko LargeFieldElement tmp; 175f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memset(&tmp, 0, sizeof(tmp)); 176f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 177f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 178f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int j = 0; j < 8; j++) { 17924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko tmp[i + j] += static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(b[j]); 180f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 181f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 182f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 183f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ReduceLarge(out, &tmp); 184f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 185f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 186f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Square computes *out = a*a 187f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 188f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// a[i] < 2**29 189f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// out[i] < 2**29 190f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Square(FieldElement* out, const FieldElement& a) { 191f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko LargeFieldElement tmp; 192f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memset(&tmp, 0, sizeof(tmp)); 193f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 194f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 195f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int j = 0; j <= i; j++) { 19624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint64_t r = static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(a[j]); 197f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (i == j) { 198f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko tmp[i+j] += r; 199f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } else { 200f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko tmp[i+j] += r << 1; 201f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 202f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 203f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 204f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 205f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ReduceLarge(out, &tmp); 206f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 207f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 208f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Reduce reduces the coefficients of in_out to smaller bounds. 209f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 210f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// On entry: a[i] < 2**31 + 2**30 211f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// On exit: a[i] < 2**29 212f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Reduce(FieldElement* in_out) { 213f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement& a = *in_out; 214f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 215f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 7; i++) { 216f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[i+1] += a[i] >> 28; 217f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[i] &= kBottom28Bits; 218f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 21924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t top = a[7] >> 28; 220f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[7] &= kBottom28Bits; 221f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 222f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // top < 2**4 223f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Constant-time: mask = (top != 0) ? 0xffffffff : 0 22424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t mask = top; 225f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko mask |= mask >> 2; 226f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko mask |= mask >> 1; 227f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko mask <<= 31; 22824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko mask = static_cast<uint32_t>(static_cast<int32_t>(mask) >> 31); 229f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 230f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Eliminate top while maintaining the same value mod p. 231f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[0] -= top; 232f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[3] += top << 12; 233f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 234f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // We may have just made a[0] negative but, if we did, then we must 235f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // have added something to a[3], thus it's > 2**12. Therefore we can 236f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // carry down to a[0]. 237f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[3] -= 1 & mask; 238f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[2] += mask & ((1<<28) - 1); 239f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[1] += mask & ((1<<28) - 1); 240f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko a[0] += mask & (1<<28); 241f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 242f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 243f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), i.e. 244f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Fermat's little theorem. 245f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Invert(FieldElement* out, const FieldElement& in) { 246f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement f1, f2, f3, f4; 247f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 248f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f1, in); // 2 249f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f1, f1, in); // 2**2 - 1 250f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f1, f1); // 2**3 - 2 251f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f1, f1, in); // 2**3 - 1 252f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f1); // 2**4 - 2 253f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f2); // 2**5 - 4 254f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f2); // 2**6 - 8 255f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f1, f1, f2); // 2**6 - 1 256f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f1); // 2**7 - 2 257f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 5; i++) { // 2**12 - 2**6 258f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f2); 259f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 260f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f2, f2, f1); // 2**12 - 1 261f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f3, f2); // 2**13 - 2 262f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 11; i++) { // 2**24 - 2**12 263f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f3, f3); 264f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 265f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f2, f3, f2); // 2**24 - 1 266f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f3, f2); // 2**25 - 2 267f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 23; i++) { // 2**48 - 2**24 268f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f3, f3); 269f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 270f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f3, f3, f2); // 2**48 - 1 271f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f4, f3); // 2**49 - 2 272f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 47; i++) { // 2**96 - 2**48 273f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f4, f4); 274f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 275f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f3, f3, f4); // 2**96 - 1 276f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f4, f3); // 2**97 - 2 277f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 23; i++) { // 2**120 - 2**24 278f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f4, f4); 279f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 280f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f2, f4, f2); // 2**120 - 1 281f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 6; i++) { // 2**126 - 2**6 282f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f2, f2); 283f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 284f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f1, f1, f2); // 2**126 - 1 285f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f1, f1); // 2**127 - 2 286f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&f1, f1, in); // 2**127 - 1 287f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 97; i++) { // 2**224 - 2**97 288f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&f1, f1); 289f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 290f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(out, f1, f3); // 2**224 - 2**96 - 1 291f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 292f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 293f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Contract converts a FieldElement to its minimal, distinguished form. 294f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 295f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// On entry, in[i] < 2**29 296f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// On exit, in[i] < 2**28 297f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Contract(FieldElement* inout) { 298f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement& out = *inout; 299f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 300f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Reduce the coefficients to < 2**28. 301f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 7; i++) { 302f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i+1] += out[i] >> 28; 303f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i] &= kBottom28Bits; 304f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 30524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t top = out[7] >> 28; 306f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[7] &= kBottom28Bits; 307f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 308f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Eliminate top while maintaining the same value mod p. 309f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[0] -= top; 310f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[3] += top << 12; 311f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 312f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // We may just have made out[0] negative. So we carry down. If we made 313f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // out[0] negative then we know that out[3] is sufficiently positive 314f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // because we just added to it. 315f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 3; i++) { 31624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31); 317f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i] += (1 << 28) & mask; 318f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i+1] -= 1 & mask; 319f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 320f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 321f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // We might have pushed out[3] over 2**28 so we perform another, partial 322f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // carry chain. 323f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 3; i < 7; i++) { 324f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i+1] += out[i] >> 28; 325f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i] &= kBottom28Bits; 326f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 327f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top = out[7] >> 28; 328f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[7] &= kBottom28Bits; 329f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 330f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Eliminate top while maintaining the same value mod p. 331f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[0] -= top; 332f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[3] += top << 12; 333f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 334f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // There are two cases to consider for out[3]: 335f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 1) The first time that we eliminated top, we didn't push out[3] over 336f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 2**28. In this case, the partial carry chain didn't change any values 337f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // and top is zero. 338f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 2) We did push out[3] over 2**28 the first time that we eliminated top. 339f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The first value of top was in [0..16), therefore, prior to eliminating 340f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after 341f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // overflowing and being reduced by the second carry chain, out[3] <= 342f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // 0xf000. Thus it cannot have overflowed when we eliminated top for the 343f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // second time. 344f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 345f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Again, we may just have made out[0] negative, so do the same carry down. 346f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // As before, if we made out[0] negative then we know that out[3] is 347f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // sufficiently positive. 348f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 3; i++) { 34924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31); 350f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i] += (1 << 28) & mask; 351f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[i+1] -= 1 & mask; 352f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 353f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 354f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The value is < 2**224, but maybe greater than p. In order to reduce to a 355f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // unique, minimal value we see if the value is >= p and, if so, subtract p. 356f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 357f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // First we build a mask from the top four limbs, which must all be 358f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones 359f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // ends up with any zero bits in the bottom 28 bits, then this wasn't 360f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // true. 36124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t top_4_all_ones = 0xffffffffu; 362f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 4; i < 8; i++) { 363f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= out[i]; 364f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 365f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones |= 0xf0000000; 366f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Now we replicate any zero bits to all the bits in top_4_all_ones. 367f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= top_4_all_ones >> 16; 368f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= top_4_all_ones >> 8; 369f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= top_4_all_ones >> 4; 370f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= top_4_all_ones >> 2; 371f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones &= top_4_all_ones >> 1; 372f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko top_4_all_ones = 37324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko static_cast<uint32_t>(static_cast<int32_t>(top_4_all_ones << 31) >> 31); 374f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 375f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Now we test whether the bottom three limbs are non-zero. 37624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t bottom_3_non_zero = out[0] | out[1] | out[2]; 377f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero |= bottom_3_non_zero >> 16; 378f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero |= bottom_3_non_zero >> 8; 379f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero |= bottom_3_non_zero >> 4; 380f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero |= bottom_3_non_zero >> 2; 381f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero |= bottom_3_non_zero >> 1; 382f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko bottom_3_non_zero = 38324854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko static_cast<uint32_t>(static_cast<int32_t>(bottom_3_non_zero) >> 31); 384f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 385f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Everything depends on the value of out[3]. 386f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p 387f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0, 388f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // then the whole value is >= p 389f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If it's < 0xffff000, then the whole value is < p 39024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t n = out[3] - 0xffff000; 39124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t out_3_equal = n; 392f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal |= out_3_equal >> 16; 393f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal |= out_3_equal >> 8; 394f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal |= out_3_equal >> 4; 395f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal |= out_3_equal >> 2; 396f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal |= out_3_equal >> 1; 397f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out_3_equal = 39824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko ~static_cast<uint32_t>(static_cast<int32_t>(out_3_equal << 31) >> 31); 399f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 400f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If out[3] > 0xffff000 then n's MSB will be zero. 40124854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t out_3_gt = 40224854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko ~static_cast<uint32_t>(static_cast<int32_t>(n << 31) >> 31); 403f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 40424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t mask = 40524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt); 406f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[0] -= 1 & mask; 407f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[3] -= 0xffff000 & mask; 408f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[4] -= 0xfffffff & mask; 409f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[5] -= 0xfffffff & mask; 410f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[6] -= 0xfffffff & mask; 411f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[7] -= 0xfffffff & mask; 412f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 413f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 414f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 415f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Group element functions. 416f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 417f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// These functions deal with group elements. The group is an elliptic curve 418f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// group with a = -3 defined in FIPS 186-3, section D.2.2. 419f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 420f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkousing crypto::p224::Point; 421f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 422f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// kB is parameter of the elliptic curve. 423f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoconst FieldElement kB = { 424f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 55967668, 11768882, 265861671, 185302395, 425f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 39211076, 180311059, 84673715, 188764328, 426f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 427f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 42824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid CopyConditional(Point* out, const Point& a, uint32_t mask); 429f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid DoubleJacobian(Point* out, const Point& a); 430f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 431f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// AddJacobian computes *out = a+b where a != b. 432f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid AddJacobian(Point *out, 433f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const Point& a, 434f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko const Point& b) { 435f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl 436f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; 437f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 43824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t z1_is_zero = IsZero(a.z); 43924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t z2_is_zero = IsZero(b.z); 440f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 441f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Z1Z1 = Z1² 442f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&z1z1, a.z); 443f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 444f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Z2Z2 = Z2² 445f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&z2z2, b.z); 446f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 447f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // U1 = X1*Z2Z2 448f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&u1, a.x, z2z2); 449f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 450f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // U2 = X2*Z1Z1 451f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&u2, b.x, z1z1); 452f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 453f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // S1 = Y1*Z2*Z2Z2 454f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&s1, b.z, z2z2); 455f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&s1, a.y, s1); 456f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 457f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // S2 = Y2*Z1*Z1Z1 458f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&s2, a.z, z1z1); 459f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&s2, b.y, s2); 460f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 461f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // H = U2-U1 462f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&h, u2, u1); 463f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&h); 46424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t x_equal = IsZero(h); 465f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 466f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // I = (2*H)² 467f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int k = 0; k < 8; k++) { 468f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko i[k] = h[k] << 1; 469f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 470f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&i); 471f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&i, i); 472f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 473f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // J = H*I 474f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&j, h, i); 475f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // r = 2*(S2-S1) 476f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&r, s2, s1); 477f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&r); 47824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t y_equal = IsZero(r); 479f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 480f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { 481f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // The two input points are the same therefore we must use the dedicated 482f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // doubling function as the slope of the line is undefined. 483f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DoubleJacobian(out, a); 484f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return; 485f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 486f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 487f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int k = 0; k < 8; k++) { 488f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko r[k] <<= 1; 489f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 490f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&r); 491f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 492f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // V = U1*I 493f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&v, u1, i); 494f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 495f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H 496f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Add(&z1z1, z1z1, z2z2); 497f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Add(&z2z2, a.z, b.z); 498f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&z2z2); 499f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&z2z2, z2z2); 500f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->z, z2z2, z1z1); 501f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->z); 502f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&out->z, out->z, h); 503f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 504f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // X3 = r²-J-2*V 505f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int k = 0; k < 8; k++) { 506f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko z1z1[k] = v[k] << 1; 507f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 508f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Add(&z1z1, j, z1z1); 509f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&z1z1); 510f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&out->x, r); 511f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->x, out->x, z1z1); 512f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->x); 513f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 514f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Y3 = r*(V-X3)-2*S1*J 515f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int k = 0; k < 8; k++) { 516f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko s1[k] <<= 1; 517f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 518f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&s1, s1, j); 519f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&z1z1, v, out->x); 520f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&z1z1); 521f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&z1z1, z1z1, r); 522f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->y, z1z1, s1); 523f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->y); 524f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 525f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CopyConditional(out, a, z2_is_zero); 526f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CopyConditional(out, b, z1_is_zero); 527f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 528f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 529f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// DoubleJacobian computes *out = a+a. 530f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid DoubleJacobian(Point* out, const Point& a) { 531f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b 532f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement delta, gamma, beta, alpha, t; 533f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 534f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&delta, a.z); 535f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&gamma, a.y); 536f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&beta, a.x, gamma); 537f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 538f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // alpha = 3*(X1-delta)*(X1+delta) 539f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Add(&t, a.x, delta); 540f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 541f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko t[i] += t[i] << 1; 542f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 543f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&t); 544f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&alpha, a.x, delta); 545f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&alpha); 546f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&alpha, alpha, t); 547f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 548f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Z3 = (Y1+Z1)²-gamma-delta 549f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Add(&out->z, a.y, a.z); 550f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->z); 551f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&out->z, out->z); 552f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->z, out->z, gamma); 553f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->z); 554f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->z, out->z, delta); 555f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->z); 556f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 557f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // X3 = alpha²-8*beta 558f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 559f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko delta[i] = beta[i] << 3; 560f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 561f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&delta); 562f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&out->x, alpha); 563f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->x, out->x, delta); 564f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->x); 565f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 566f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Y3 = alpha*(4*beta-X3)-8*gamma² 567f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 568f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko beta[i] <<= 2; 569f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 570f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&beta); 571f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&beta, beta, out->x); 572f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&beta); 573f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&gamma, gamma); 574f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 575f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko gamma[i] <<= 3; 576f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 577f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&gamma); 578f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&out->y, alpha, beta); 579f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->y, out->y, gamma); 580f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->y); 581f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 582f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 583f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 of 584f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// 0xffffffff. 58524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid CopyConditional(Point* out, const Point& a, uint32_t mask) { 586f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 587f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out->x[i] ^= mask & (a.x[i] ^ out->x[i]); 588f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out->y[i] ^= mask & (a.y[i] ^ out->y[i]); 589f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out->z[i] ^= mask & (a.z[i] ^ out->z[i]); 590f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 591f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 592f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 593f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// ScalarMult calculates *out = a*scalar where scalar is a big-endian number of 594f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// length scalar_len and != 0. 59524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid ScalarMult(Point* out, 59624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko const Point& a, 59724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko const uint8_t* scalar, 59824854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko size_t scalar_len) { 599f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memset(out, 0, sizeof(*out)); 600f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Point tmp; 601f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 602f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (size_t i = 0; i < scalar_len; i++) { 603f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (unsigned int bit_num = 0; bit_num < 8; bit_num++) { 604f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko DoubleJacobian(out, *out); 60524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t bit = static_cast<uint32_t>(static_cast<int32_t>( 606f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (((scalar[i] >> (7 - bit_num)) & 1) << 31) >> 31)); 607f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko AddJacobian(&tmp, a, *out); 608f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko CopyConditional(out, tmp, bit); 609f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 610f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 611f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 612f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 613f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Get224Bits reads 7 words from in and scatters their contents in 614f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// little-endian form into 8 words at out, 28 bits per output word. 61524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid Get224Bits(uint32_t* out, const uint32_t* in) { 616f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[0] = NetToHost32(in[6]) & kBottom28Bits; 617f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[1] = ((NetToHost32(in[5]) << 4) | 618f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[6]) >> 28)) & kBottom28Bits; 619f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[2] = ((NetToHost32(in[4]) << 8) | 620f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[5]) >> 24)) & kBottom28Bits; 621f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[3] = ((NetToHost32(in[3]) << 12) | 622f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[4]) >> 20)) & kBottom28Bits; 623f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[4] = ((NetToHost32(in[2]) << 16) | 624f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[3]) >> 16)) & kBottom28Bits; 625f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[5] = ((NetToHost32(in[1]) << 20) | 626f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[2]) >> 12)) & kBottom28Bits; 627f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[6] = ((NetToHost32(in[0]) << 24) | 628f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko (NetToHost32(in[1]) >> 8)) & kBottom28Bits; 629f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[7] = (NetToHost32(in[0]) >> 4) & kBottom28Bits; 630f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 631f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 632f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from 633f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// each of 8 input words and writing them in big-endian order to 7 words at 634f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// out. 63524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid Put224Bits(uint32_t* out, const uint32_t* in) { 636f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[6] = HostToNet32((in[0] >> 0) | (in[1] << 28)); 637f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[5] = HostToNet32((in[1] >> 4) | (in[2] << 24)); 638f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[4] = HostToNet32((in[2] >> 8) | (in[3] << 20)); 639f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[3] = HostToNet32((in[3] >> 12) | (in[4] << 16)); 640f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[2] = HostToNet32((in[4] >> 16) | (in[5] << 12)); 641f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[1] = HostToNet32((in[5] >> 20) | (in[6] << 8)); 642f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out[0] = HostToNet32((in[6] >> 24) | (in[7] << 4)); 643f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 644f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 645f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // anonymous namespace 646f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 647f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace crypto { 648f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 649f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace p224 { 650f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 651f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkobool Point::SetFromString(const base::StringPiece& in) { 652f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (in.size() != 2*28) 653f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return false; 65424854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko const uint32_t* inwords = reinterpret_cast<const uint32_t*>(in.data()); 655f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Get224Bits(x, inwords); 656f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Get224Bits(y, inwords + 7); 657f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memset(&z, 0, sizeof(z)); 658f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko z[0] = 1; 659f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 660f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Check that the point is on the curve, i.e. that y² = x³ - 3x + b. 661f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement lhs; 662f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&lhs, y); 663f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Contract(&lhs); 664f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 665f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement rhs; 666f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&rhs, x); 667f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&rhs, x, rhs); 668f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 669f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement three_x; 670f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko for (int i = 0; i < 8; i++) { 671f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko three_x[i] = x[i] * 3; 672f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 673f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&three_x); 674f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&rhs, rhs, three_x); 675f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&rhs); 676f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 677f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ::Add(&rhs, rhs, kB); 678f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Contract(&rhs); 679f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; 680f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 681f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 682f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkostd::string Point::ToString() const { 683f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement zinv, zinv_sq, xx, yy; 684f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 685f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // If this is the point at infinity we return a string of all zeros. 686f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko if (IsZero(this->z)) { 687f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko static const char zeros[56] = {0}; 688f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return std::string(zeros, sizeof(zeros)); 689f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko } 690f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 691f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Invert(&zinv, this->z); 692f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&zinv_sq, zinv); 693f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&xx, x, zinv_sq); 694f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&zinv_sq, zinv_sq, zinv); 695f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&yy, y, zinv_sq); 696f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 697f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Contract(&xx); 698f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Contract(&yy); 699f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 70024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko uint32_t outwords[14]; 701f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Put224Bits(outwords, xx); 702f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Put224Bits(outwords + 7, yy); 703f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords)); 704f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 705f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 70624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid ScalarMult(const Point& in, const uint8_t* scalar, Point* out) { 707f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ::ScalarMult(out, in, scalar, 28); 708f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 709f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 710f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// kBasePoint is the base point (generator) of the elliptic curve group. 711f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkostatic const Point kBasePoint = { 712f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko {22813985, 52956513, 34677300, 203240812, 713f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 12143107, 133374265, 225162431, 191946955}, 714f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko {83918388, 223877528, 122119236, 123340192, 715f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 266784067, 263504429, 146143011, 198407736}, 716f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko {1, 0, 0, 0, 0, 0, 0, 0}, 717f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}; 718f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 71924854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenkovoid ScalarBaseMult(const uint8_t* scalar, Point* out) { 720f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko ::ScalarMult(out, kBasePoint, scalar, 28); 721f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 722f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 723f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Add(const Point& a, const Point& b, Point* out) { 724f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko AddJacobian(out, a, b); 725f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 726f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 727f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkovoid Negate(const Point& in, Point* out) { 728f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // Guide to elliptic curve cryptography, page 89 suggests that (X : X+Y : Z) 729f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // is the negative in Jacobian coordinates, but it doesn't actually appear to 730f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko // be true in testing so this performs the negation in affine coordinates. 731f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko FieldElement zinv, zinv_sq, y; 732f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Invert(&zinv, in.z); 733f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Square(&zinv_sq, zinv); 734f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&out->x, in.x, zinv_sq); 735f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&zinv_sq, zinv_sq, zinv); 736f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Mul(&y, in.y, zinv_sq); 737f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 738f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Subtract(&out->y, kP, y); 739f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko Reduce(&out->y); 740f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 741f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko memset(&out->z, 0, sizeof(out->z)); 742f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko out->z[0] = 1; 743f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} 744f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 745f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace p224 746f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko 747f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko} // namespace crypto 748