Skip to content

[WIP] feat: pq sig - #944

Draft
Argimirodelpozo wants to merge 27 commits into
algorand:mainfrom
Argimirodelpozo:feat/pq
Draft

[WIP] feat: pq sig#944
Argimirodelpozo wants to merge 27 commits into
algorand:mainfrom
Argimirodelpozo:feat/pq

Conversation

@Argimirodelpozo

@Argimirodelpozo Argimirodelpozo commented Aug 21, 2026

Copy link
Copy Markdown

[WIP]

Note that the falcon-det1024 package is vendored in, using this. When that one is properly published, we can use it as a regular dep. instead, same as the rest of SDKs.

…ote fields, app args, extra app pages, lsig size)
…BoxRef types used boxed Long/byte[] fields, so NON_DEFAULT serialization never suppressed zero indices or empty box names, breaking access list usage of index 0 shorthands
…not set, causing msgpack key set to nil instead of being actually absent

@mrcointreau mrcointreau left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Addresses, signing preimages, wire format and test vectors match js and py implementations with no breaking changes. The real differences between the Java implementation and the js/py ones are at design-level:

  1. Non-canonical salt management: Java resolves a pqsig's address from the salt it carries, as-is while js/py reject non-canonical salts.
  2. Verification methods: in js/py verify() was deprecated and returns false for pqsigs, since we can't check validity without the falcon package; Java returns true on the address-envelope match (partly because Account.signLogicTransactionWithAddress gates signing on verify()). If we decide to align Java, the fix is contained and non-breaking: return false + move the envelope check into the signing path.
  3. Vendored falcon-det1024: currently used by the cucumber steps and the falcon vector unit tests, goes away once the library is on Maven Central. One thing to fix before the next release regardless: the top-level <repositories> block ships verbatim in the published pom (which is immutable), so swap it for an install-file step or scope it in a profile.

We could ship this as-is and refine it later on, I'd ask @joe-p to be sure about the plan.

*/
public static Address fromSignature(PQSignature pqsig) throws NoSuchAlgorithmException {
Objects.requireNonNull(pqsig, "pqsig must not be null");
return derive(pqsig.scheme, pqsig.salt, pqsig.publicKey);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just flagging a divergence: js/py reject a pqsig whose salt is not the canonical one, while here the address is resolved from the carried salt as-is (matching go consensus), with explicit-salt APIs on top. So the same blob raises in js/py and works in Java. This may well be fine, just worth knowing the implementations differ.

@Argimirodelpozo Argimirodelpozo Aug 22, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This divergence came from a talk with @iglosiggio and how he was approaching this in golang. He made a good point that if for whatever reason somebody has a non-canonical salt sig, and this is valid for consensus, then we should really support it even if on generation we prioritize the canonical salt.
I do believe it's worth keeping parity as strictly as possible between SDKs, so we should decide what we want to do in general when we do a 4-sdk-wide parity review.

Comment thread src/test/java/com/algorand/algosdk/crypto/TestPQ.java Outdated
Comment thread src/test/java/com/algorand/algosdk/crypto/TestPQ.java Outdated
// delegating account. go-algorand-sdk's VerifyLogicSig skips post-
// quantum signatures entirely and returns true.
try {
return PQAddress.fromSignature(this.pqsig).equals(singleSigner);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Another divergence to be aware of: js/py sdks deprecated verify() and return false for a pqsig (the SDK can't validate falcon locally), while here it returns true when the address derived from the envelope matches, without reading the signature bytes. Java kept true because signLogicTransactionWithAddress gates signing on verify. Could be fine either way, just worth knowing the implementations differ.

Comment thread pom.xml
Comment on lines +227 to +234
<repositories>
<repository>
<id>vendored-test-lib</id>
<url>file://${project.basedir}/test-lib</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

test-lib/README.md already covers removing this once falcon-det1024 hits Maven Central, but there's no guard for the opposite ordering: if an SDK release goes out first, this block ships in the (immutable) published pom, since both deploy paths publish the raw pom and there's no flatten plugin. If a release could plausibly land before the falcon publish, cheap insurance is moving the block inside a profile or resolving the jar via an install-file step; otherwise fine as-is.

* @param signer the post-quantum signer of the delegating account
* @return a delegated LogicSigAccount carrying the post-quantum signature
*/
public static LogicSigAccount delegatedPQ(byte[] logic, List<byte[]> args, PQAlgorandSigner signer)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PQ got one-call factories (delegatedPQ/delegatedFalcon1024) but there's no ed25519-callback equivalent, while js/py cover both with signWithSigner/sign_with_signer. The two-step composition works (signLogicsig + the verifying ctor), so just a nit: consider a matching delegated(logic, args, Ed25519AlgorandSigner) factory

Comment thread src/main/java/com/algorand/algosdk/signer/Ed25519AlgorandSigner.java Outdated
Comment thread src/main/java/com/algorand/algosdk/signer/Ed25519MultisigAlgorandSigner.java Outdated
Argimirodelpozo and others added 4 commits August 22, 2026 23:41
…r.java

Co-authored-by: mrcointreau <45950216+mrcointreau@users.noreply.github.com>
…andSigner.java

Co-authored-by: mrcointreau <45950216+mrcointreau@users.noreply.github.com>
Co-authored-by: mrcointreau <45950216+mrcointreau@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants