void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s) { // TODO: mutex ASN1::secp256k1() singleton // Creating Domain is non-const for m_oid and m_oid is not thread-safe ECDH<ECP>::Domain d(ASN1::secp256k1()); assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; memcpy(&remote[1], _r.data(), 64); d.Agree(o_s.writable().data(), _s.data(), remote); }
void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p) { bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); { Guard l(x_params); m_params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); } memcpy(o_p.data(), &prefixedKey[1], Public::size); }
void ECDHEKeyExchange::exchange(bytes& o_exchange) { if (!m_ephemeralSecret) // didn't agree on public remote BOOST_THROW_EXCEPTION(InvalidState()); // The key exchange payload is in two parts and is encrypted // using ephemeral keypair. // // The first part is the 'prefix' which is a zero-knowledge proof // allowing the remote to resume or emplace a previous session. // If a session previously exists: // prefix is sha3(token) // todo: ephemeral entropy from both sides // If a session doesn't exist: // prefix is sha3(m_ephemeralSecret) // // The second part is encrypted using the public key which relates to the prefix. Public encpk = m_known.first ? m_known.first : m_remoteEphemeral; bytes exchange(encpk.asBytes()); // This is the public key which we would like the remote to use, // which maybe different than the previously-known public key. // // Here we should pick an appropriate alias or generate a new one, // but for now, we use static alias passed to constructor. // Public p = toPublic(m_alias.m_secret); exchange.resize(exchange.size() + sizeof(p)); memcpy(&exchange[exchange.size() - sizeof(p)], p.data(), sizeof(p)); // protocol parameters; should be fixed size bytes v(1, 0x80); exchange.resize(exchange.size() + v.size()); memcpy(&exchange[exchange.size() - v.size()], v.data(), v.size()); h256 auth; sha3mac(m_alias.m_secret.ref(), m_ephemeralSecret.ref(), auth.ref()); Signature sig = s_secp256k1.sign(m_alias.m_secret, auth); exchange.resize(exchange.size() + sizeof(sig)); memcpy(&exchange[exchange.size() - sizeof(sig)], sig.data(), sizeof(sig)); aes::AuthenticatedStream aes(aes::Encrypt, m_ephemeralSecret, 0); h256 prefix(sha3(m_known.second ? m_known.second : (h256)m_remoteEphemeral)); aes.update(prefix.ref()); s_secp256k1.encrypt(encpk, exchange); aes.update(&exchange); aes.streamOut(o_exchange); }
Public Secp256k1PP::recover(Signature _signature, bytesConstRef _message) { Public recovered; Integer r(_signature.data(), 32); Integer s(_signature.data()+32, 32); // cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28 byte encodedpoint[33]; encodedpoint[0] = _signature[64] | 2; memcpy(&encodedpoint[1], _signature.data(), 32); ECP::Element x; { m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; } // if (_signature[64] & 2) // { // r += m_q; // Guard l(x_params); // if (r >= m_params.GetMaxExponent()) // return recovered; // } Integer z(_message.data(), 32); Integer rn = r.InverseMod(m_q); Integer u1 = m_q - (rn.Times(z)).Modulo(m_q); Integer u2 = (rn.Times(s)).Modulo(m_q); ECP::Point p; byte recoveredbytes[65]; { // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); if (p.identity) return Public(); m_curve.EncodePoint(recoveredbytes, p, false); } memcpy(recovered.data(), &recoveredbytes[1], 64); return recovered; }