Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[seraphis] seraphis_crypto: add seraphis transcript utility #8990

Merged
merged 2 commits into from
Nov 6, 2023

Conversation

UkoeHB
Copy link
Contributor

@UkoeHB UkoeHB commented Sep 10, 2023

Summary

This is a PR in my 'upstreaming seraphis_lib project', it is not used anywhere yet.

  • Adds src/seraphis_crypto directory. Includes a dummy cpp file so cmake won't complain (will remove it once I have a cpp file to add).
  • Adds sp_transcript.h to seraphis_crypto.

Explanation

In the current codebase, transcripting of crypto protocols is done manually which is verbose and inflexible. I wrote a transcripting utility that is quite ergonomic and has served me well in the seraphis library.

There are two modes

  • SpFSTranscript: Fiat-Shamir transcript, includes labels, type flags, and type lengths. Suited for variable-length transcripts. Should be used for Fiat-Shamir challenges.
  • SpKDFTranscript: KDF transcript, does not include labels, type flags, or type lengths. Suited for short fixed-length transcripts (e.g. key derivations). In my seraphis library all uses of KDF transcripts are less than 128 bytes (or 256 bytes at least, can't remember).

Example use:

// my_proof.h
struct MyProof
{
    rct::key A;
};
inline const boost::string_ref container_name(const MyProof&) { return "MyProof"; }
void append_to_transcript(const MyProof &container, SpTranscriptBuilder &transcript_inout);

// my_proof.cpp
void append_to_transcript(const MyProof &container, SpTranscriptBuilder &transcript_inout)
{
    transcript_inout.append("A", container.A);
}

// build a transcript and consume it
rct::key make_challenge(const proof &P)
{
    // hash data
    SpFSTranscript transcript{config::HASH_KEY_MY_CHALLENGE, sizeof(rct::key)};
    transcript.append("proof", proof);

    // challenge
    rct::key challenge;
    sp_hash_to_scalar(transcript.data(), transcript.size(), challenge.bytes);

    return challenge;
}

Copy link
Contributor

@vtnerd vtnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but there is one thing that definitely needs to be changed (the signed integer code).

if (m_mode == Mode::SIMPLE)
return;

static_assert(sizeof(std::size_t) <= sizeof(std::uint64_t), "");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static_assert(std::numeric_limits<std::size_t>::max() <= std::numeric_limits<std::uint64_t>::max()`, "")

is probably the most accurate. Although, I'm not sure of any scenarios where your check fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect a LOT of old C/C++ code would break if these checks ever became invalid.

src/seraphis_crypto/sp_transcript.h Outdated Show resolved Hide resolved
src/seraphis_crypto/sp_transcript.h Show resolved Hide resolved
{
// negative integer: byte{1} || varint(uint(abs(int_variable)))
this->append_uint(1);
this->append_uint(static_cast<std::uint64_t>(-signed_integer));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can overflow if std::numeric_limits<T>::min() and the platform is using 2s complement (the most common). I think this works on all platforms though:

using unsigned_type = std::make_unsigned<T>::type;
static_assert(sizeof(unsigned_type) <= sizeof(std::uint64_t), "");
this->append_uint(static_cast<unsigned_type>(signed_integer));

This stack overflow might be helpful.

Copy link
Contributor Author

@UkoeHB UkoeHB Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice catch. Technically my approach is sound because it will only wrap to zero, which is treated as a positive integer normally so there is no malleability. However better to be absolutely correct here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I didn't think of that. You'd have a positive and negative zero.

Copy link
Contributor

@vtnerd vtnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I thought this wasn't submitted.

@selsta
Copy link
Collaborator

selsta commented Oct 13, 2023

@vtnerd could you re-review and potentially approve?


//local headers
#include "crypto/crypto.h"
#include "crypto/x25519.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find this header, is this new? The checks still pass, so I must be missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah x25519 is not PRd yet, I will remove that code from here and re-add it with the x25519 PR.

@luigi1111 luigi1111 merged commit 54e8463 into monero-project:master Nov 6, 2023
18 checks passed
@UkoeHB UkoeHB deleted the sp_transcript branch February 22, 2024 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants